| Directory: | ./ |
|---|---|
| File: | storage/innobase/handler/handler0alter.cc |
| Date: | 2022-11-26 14:12:44 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 4172 | 4776 | 87.4% |
| Branches: | 3842 | 6423 | 59.8% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /***************************************************************************** | ||
| 2 | |||
| 3 | Copyright (c) 2005, 2022, Oracle and/or its affiliates. | ||
| 4 | |||
| 5 | This program is free software; you can redistribute it and/or modify it under | ||
| 6 | the terms of the GNU General Public License, version 2.0, as published by the | ||
| 7 | Free Software Foundation. | ||
| 8 | |||
| 9 | This program is also distributed with certain software (including but not | ||
| 10 | limited to OpenSSL) that is licensed under separate terms, as designated in a | ||
| 11 | particular file or component or in included license documentation. The authors | ||
| 12 | of MySQL hereby grant you an additional permission to link the program and | ||
| 13 | your derivative works with the separately licensed software that they have | ||
| 14 | included with MySQL. | ||
| 15 | |||
| 16 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 18 | FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, | ||
| 19 | for more details. | ||
| 20 | |||
| 21 | You should have received a copy of the GNU General Public License along with | ||
| 22 | this program; if not, write to the Free Software Foundation, Inc., | ||
| 23 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 24 | |||
| 25 | *****************************************************************************/ | ||
| 26 | |||
| 27 | /** @file handler/handler0alter.cc | ||
| 28 | Smart ALTER TABLE | ||
| 29 | *******************************************************/ | ||
| 30 | |||
| 31 | /* Include necessary SQL headers */ | ||
| 32 | #include <assert.h> | ||
| 33 | #include <current_thd.h> | ||
| 34 | #include <debug_sync.h> | ||
| 35 | #include <key_spec.h> | ||
| 36 | #include <log.h> | ||
| 37 | #include <my_bit.h> | ||
| 38 | #include <mysql/plugin.h> | ||
| 39 | #include <sql_class.h> | ||
| 40 | #include <sql_lex.h> | ||
| 41 | #include <sql_table.h> | ||
| 42 | #include <sql_thd_internal_api.h> | ||
| 43 | #include <sys/types.h> | ||
| 44 | #include "ha_prototypes.h" | ||
| 45 | |||
| 46 | #include "dd/cache/dictionary_client.h" | ||
| 47 | #include "dd/dd.h" | ||
| 48 | #include "dd/dictionary.h" | ||
| 49 | #include "dd/impl/properties_impl.h" | ||
| 50 | #include "dd/impl/types/column_impl.h" | ||
| 51 | #include "dd/properties.h" | ||
| 52 | #include "dd/types/column.h" | ||
| 53 | #include "dd/types/column_type_element.h" | ||
| 54 | #include "dd/types/index.h" | ||
| 55 | #include "dd/types/index_element.h" | ||
| 56 | #include "dd/types/partition.h" | ||
| 57 | #include "dd/types/partition_index.h" | ||
| 58 | #include "dd/types/table.h" | ||
| 59 | #include "dd/types/tablespace_file.h" | ||
| 60 | #include "dd_table_share.h" | ||
| 61 | |||
| 62 | #include "btr0sea.h" | ||
| 63 | #include "dict0crea.h" | ||
| 64 | #include "dict0dd.h" | ||
| 65 | #include "dict0dict.h" | ||
| 66 | #include "dict0inst.h" //Instant DDL | ||
| 67 | #include "dict0priv.h" | ||
| 68 | #include "dict0stats.h" | ||
| 69 | #include "dict0stats_bg.h" | ||
| 70 | #include "fsp0sysspace.h" | ||
| 71 | #include "fts0plugin.h" | ||
| 72 | #include "fts0priv.h" | ||
| 73 | #include "ha_innodb.h" | ||
| 74 | #include "ha_innopart.h" | ||
| 75 | #include "ha_prototypes.h" | ||
| 76 | #include "handler0alter.h" | ||
| 77 | #include "lex_string.h" | ||
| 78 | #include "log0buf.h" | ||
| 79 | #include "log0chkp.h" | ||
| 80 | |||
| 81 | #include "my_dbug.h" | ||
| 82 | #include "my_io.h" | ||
| 83 | |||
| 84 | #include "clone0api.h" | ||
| 85 | #include "ddl0ddl.h" | ||
| 86 | #include "dict0dd.h" | ||
| 87 | #include "fts0plugin.h" | ||
| 88 | #include "fts0priv.h" | ||
| 89 | #include "handler0alter.h" | ||
| 90 | #include "lock0lock.h" | ||
| 91 | #include "pars0pars.h" | ||
| 92 | #include "partition_info.h" | ||
| 93 | #include "rem0types.h" | ||
| 94 | #include "row0ins.h" | ||
| 95 | #include "row0log.h" | ||
| 96 | #include "row0sel.h" | ||
| 97 | #include "sql/create_field.h" | ||
| 98 | #include "srv0mon.h" | ||
| 99 | #include "trx0roll.h" | ||
| 100 | #include "trx0trx.h" | ||
| 101 | #include "ut0new.h" | ||
| 102 | #include "ut0stage.h" | ||
| 103 | |||
| 104 | /* For supporting Native InnoDB Partitioning. */ | ||
| 105 | #include "ha_innopart.h" | ||
| 106 | #include "partition_info.h" | ||
| 107 | |||
| 108 | extern char server_uuid[UUID_LENGTH + 1]; | ||
| 109 | |||
| 110 | /** Function to convert the Instant_Type to a comparable int */ | ||
| 111 | 488343 | inline uint16_t instant_type_to_int(Instant_Type type) { | |
| 112 | 488343 | return (static_cast<typename std::underlying_type<Log_Type>::type>(type)); | |
| 113 | } | ||
| 114 | |||
| 115 | /** Operations for creating secondary indexes (no rebuild needed) */ | ||
| 116 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE = | ||
| 117 | Alter_inplace_info::ADD_INDEX | Alter_inplace_info::ADD_UNIQUE_INDEX | | ||
| 118 | Alter_inplace_info::ADD_SPATIAL_INDEX; | ||
| 119 | |||
| 120 | /** Operations for rebuilding a table in place */ | ||
| 121 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD = | ||
| 122 | Alter_inplace_info::ADD_PK_INDEX | Alter_inplace_info::DROP_PK_INDEX | | ||
| 123 | Alter_inplace_info::CHANGE_CREATE_OPTION | ||
| 124 | /* CHANGE_CREATE_OPTION needs to check innobase_need_rebuild() */ | ||
| 125 | | Alter_inplace_info::ALTER_COLUMN_NULLABLE | | ||
| 126 | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE | | ||
| 127 | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | | ||
| 128 | Alter_inplace_info::DROP_STORED_COLUMN | | ||
| 129 | Alter_inplace_info::ADD_STORED_BASE_COLUMN | ||
| 130 | /* ADD_STORED_BASE_COLUMN needs to check innobase_need_rebuild() */ | ||
| 131 | | Alter_inplace_info::RECREATE_TABLE; | ||
| 132 | |||
| 133 | /** Operations that require changes to data */ | ||
| 134 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_DATA = | ||
| 135 | INNOBASE_ONLINE_CREATE | INNOBASE_ALTER_REBUILD; | ||
| 136 | |||
| 137 | /** Operations for altering a table that InnoDB does not care about */ | ||
| 138 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INPLACE_IGNORE = | ||
| 139 | Alter_inplace_info::ALTER_COLUMN_DEFAULT | | ||
| 140 | Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT | | ||
| 141 | Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE | | ||
| 142 | Alter_inplace_info::ALTER_RENAME | Alter_inplace_info::CHANGE_INDEX_OPTION | | ||
| 143 | Alter_inplace_info::ADD_CHECK_CONSTRAINT | | ||
| 144 | Alter_inplace_info::DROP_CHECK_CONSTRAINT | | ||
| 145 | Alter_inplace_info::SUSPEND_CHECK_CONSTRAINT | | ||
| 146 | Alter_inplace_info::ALTER_COLUMN_VISIBILITY; | ||
| 147 | |||
| 148 | /** Operation allowed with ALGORITHM=INSTANT */ | ||
| 149 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INSTANT_ALLOWED = | ||
| 150 | Alter_inplace_info::ALTER_COLUMN_NAME | | ||
| 151 | Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 152 | Alter_inplace_info::DROP_VIRTUAL_COLUMN | | ||
| 153 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER | | ||
| 154 | Alter_inplace_info::ADD_STORED_BASE_COLUMN | | ||
| 155 | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | | ||
| 156 | Alter_inplace_info::DROP_STORED_COLUMN; | ||
| 157 | |||
| 158 | /** Operations on foreign key definitions (changing the schema only) */ | ||
| 159 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_FOREIGN_OPERATIONS = | ||
| 160 | Alter_inplace_info::DROP_FOREIGN_KEY | Alter_inplace_info::ADD_FOREIGN_KEY; | ||
| 161 | |||
| 162 | /** Operations that InnoDB cares about and can perform without rebuild */ | ||
| 163 | static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_NOREBUILD = | ||
| 164 | INNOBASE_ONLINE_CREATE | INNOBASE_FOREIGN_OPERATIONS | | ||
| 165 | Alter_inplace_info::DROP_INDEX | Alter_inplace_info::DROP_UNIQUE_INDEX | | ||
| 166 | Alter_inplace_info::RENAME_INDEX | Alter_inplace_info::ALTER_COLUMN_NAME | | ||
| 167 | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | | ||
| 168 | Alter_inplace_info::ALTER_INDEX_COMMENT | | ||
| 169 | Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 170 | Alter_inplace_info::DROP_VIRTUAL_COLUMN | | ||
| 171 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER | | ||
| 172 | Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH; | ||
| 173 | |||
| 174 | struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx { | ||
| 175 | /** Dummy query graph */ | ||
| 176 | que_thr_t *thr; | ||
| 177 | /** The prebuilt struct of the creating instance */ | ||
| 178 | row_prebuilt_t *prebuilt; | ||
| 179 | /** InnoDB indexes being created */ | ||
| 180 | dict_index_t **add_index; | ||
| 181 | /** MySQL key numbers for the InnoDB indexes that are being created */ | ||
| 182 | const ulint *add_key_numbers; | ||
| 183 | /** number of InnoDB indexes being created */ | ||
| 184 | ulint num_to_add_index; | ||
| 185 | /** InnoDB indexes being dropped */ | ||
| 186 | dict_index_t **drop_index; | ||
| 187 | /** number of InnoDB indexes being dropped */ | ||
| 188 | const ulint num_to_drop_index; | ||
| 189 | /** InnoDB indexes being renamed */ | ||
| 190 | dict_index_t **rename; | ||
| 191 | /** number of InnoDB indexes being renamed */ | ||
| 192 | const ulint num_to_rename; | ||
| 193 | /** InnoDB foreign key constraints being dropped */ | ||
| 194 | dict_foreign_t **drop_fk; | ||
| 195 | /** number of InnoDB foreign key constraints being dropped */ | ||
| 196 | const ulint num_to_drop_fk; | ||
| 197 | /** InnoDB foreign key constraints being added */ | ||
| 198 | dict_foreign_t **add_fk; | ||
| 199 | /** number of InnoDB foreign key constraints being dropped */ | ||
| 200 | const ulint num_to_add_fk; | ||
| 201 | /** whether to create the indexes online */ | ||
| 202 | bool online; | ||
| 203 | /** memory heap */ | ||
| 204 | mem_heap_t *heap; | ||
| 205 | /** dictionary transaction */ | ||
| 206 | trx_t *trx; | ||
| 207 | /** original table (if rebuilt, differs from indexed_table) */ | ||
| 208 | dict_table_t *old_table; | ||
| 209 | /** table where the indexes are being created or dropped */ | ||
| 210 | dict_table_t *new_table; | ||
| 211 | /** mapping of old column numbers to new ones, or NULL */ | ||
| 212 | const ulint *col_map; | ||
| 213 | /** new column names, or NULL if nothing was renamed */ | ||
| 214 | const char **col_names; | ||
| 215 | /** added AUTO_INCREMENT column position, or ULINT_UNDEFINED */ | ||
| 216 | const ulint add_autoinc; | ||
| 217 | /** default values of ADD COLUMN, or NULL */ | ||
| 218 | const dtuple_t *add_cols; | ||
| 219 | /** autoinc sequence to use */ | ||
| 220 | ddl::Sequence sequence; | ||
| 221 | /** maximum auto-increment value */ | ||
| 222 | ulonglong max_autoinc; | ||
| 223 | /** temporary table name to use for old table when renaming tables */ | ||
| 224 | const char *tmp_name; | ||
| 225 | /** whether the order of the clustered index is unchanged */ | ||
| 226 | bool skip_pk_sort; | ||
| 227 | /** virtual columns to be added */ | ||
| 228 | dict_v_col_t *add_vcol; | ||
| 229 | const char **add_vcol_name; | ||
| 230 | /** virtual columns to be dropped */ | ||
| 231 | dict_v_col_t *drop_vcol; | ||
| 232 | const char **drop_vcol_name; | ||
| 233 | /** ALTER TABLE stage progress recorder */ | ||
| 234 | Alter_stage *m_stage; | ||
| 235 | /** FTS AUX Tables to drop */ | ||
| 236 | aux_name_vec_t *fts_drop_aux_vec; | ||
| 237 | |||
| 238 | 47702 | ha_innobase_inplace_ctx(row_prebuilt_t *prebuilt_arg, dict_index_t **drop_arg, | |
| 239 | ulint num_to_drop_arg, dict_index_t **rename_arg, | ||
| 240 | ulint num_to_rename_arg, dict_foreign_t **drop_fk_arg, | ||
| 241 | ulint num_to_drop_fk_arg, dict_foreign_t **add_fk_arg, | ||
| 242 | ulint num_to_add_fk_arg, bool online_arg, | ||
| 243 | mem_heap_t *heap_arg, dict_table_t *new_table_arg, | ||
| 244 | const char **col_names_arg, ulint add_autoinc_arg, | ||
| 245 | ulonglong autoinc_col_min_value_arg, | ||
| 246 | ulonglong autoinc_col_max_value_arg) | ||
| 247 | 47702 | : inplace_alter_handler_ctx(), | |
| 248 | 47702 | prebuilt(prebuilt_arg), | |
| 249 | 47702 | add_index(nullptr), | |
| 250 | 47702 | add_key_numbers(nullptr), | |
| 251 | 47702 | num_to_add_index(0), | |
| 252 | 47702 | drop_index(drop_arg), | |
| 253 | 47702 | num_to_drop_index(num_to_drop_arg), | |
| 254 | 47702 | rename(rename_arg), | |
| 255 | 47702 | num_to_rename(num_to_rename_arg), | |
| 256 | 47702 | drop_fk(drop_fk_arg), | |
| 257 | 47702 | num_to_drop_fk(num_to_drop_fk_arg), | |
| 258 | 47702 | add_fk(add_fk_arg), | |
| 259 | 47702 | num_to_add_fk(num_to_add_fk_arg), | |
| 260 | 47702 | online(online_arg), | |
| 261 | 47702 | heap(heap_arg), | |
| 262 | 47702 | trx(nullptr), | |
| 263 | 47702 | old_table(prebuilt_arg->table), | |
| 264 | 47702 | new_table(new_table_arg), | |
| 265 | 47702 | col_map(nullptr), | |
| 266 | 47702 | col_names(col_names_arg), | |
| 267 | 47702 | add_autoinc(add_autoinc_arg), | |
| 268 | 47702 | add_cols(nullptr), | |
| 269 | 47702 | sequence(prebuilt->trx->mysql_thd, autoinc_col_min_value_arg, | |
| 270 | autoinc_col_max_value_arg), | ||
| 271 | 47702 | max_autoinc(0), | |
| 272 | 47702 | tmp_name(nullptr), | |
| 273 | 47702 | skip_pk_sort(false), | |
| 274 | 47702 | add_vcol(nullptr), | |
| 275 | 47702 | add_vcol_name(nullptr), | |
| 276 | 47702 | drop_vcol(nullptr), | |
| 277 | 47702 | drop_vcol_name(nullptr), | |
| 278 | 47702 | m_stage(nullptr), | |
| 279 | 47702 | fts_drop_aux_vec(nullptr) { | |
| 280 | #ifdef UNIV_DEBUG | ||
| 281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47702 times.
|
47702 | for (ulint i = 0; i < num_to_add_index; i++) { |
| 282 | ✗ | ut_ad(!add_index[i]->to_be_dropped); | |
| 283 | } | ||
| 284 |
2/2✓ Branch 0 taken 1318 times.
✓ Branch 1 taken 47702 times.
|
49020 | for (ulint i = 0; i < num_to_drop_index; i++) { |
| 285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1318 times.
|
1318 | ut_ad(drop_index[i]->to_be_dropped); |
| 286 | } | ||
| 287 | #endif /* UNIV_DEBUG */ | ||
| 288 | |||
| 289 |
1/2✓ Branch 0 taken 47702 times.
✗ Branch 1 not taken.
|
47702 | thr = pars_complete_graph_for_exec(nullptr, prebuilt->trx, heap, prebuilt); |
| 290 | 47702 | } | |
| 291 | |||
| 292 | 94196 | ~ha_innobase_inplace_ctx() override { | |
| 293 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 46990 times.
|
94196 | if (fts_drop_aux_vec != nullptr) { |
| 294 | 216 | fts_free_aux_names(fts_drop_aux_vec); | |
| 295 |
1/2✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
|
216 | delete fts_drop_aux_vec; |
| 296 | } | ||
| 297 | 94196 | ut::delete_(m_stage); | |
| 298 | 94196 | mem_heap_free(heap); | |
| 299 | } | ||
| 300 | |||
| 301 | /** Determine if the table will be rebuilt. | ||
| 302 | @return whether the table will be rebuilt */ | ||
| 303 | 886668 | bool need_rebuild() const { return (old_table != new_table); } | |
| 304 | |||
| 305 | /** Set shared data between the passed in handler context | ||
| 306 | and current context. | ||
| 307 | @param[in] ctx handler context */ | ||
| 308 | 2360 | void set_shared_data(const inplace_alter_handler_ctx *ctx) override { | |
| 309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2360 times.
|
2360 | ut_ad(ctx != nullptr); |
| 310 |
2/2✓ Branch 0 taken 2357 times.
✓ Branch 1 taken 3 times.
|
2360 | if (add_autoinc == ULINT_UNDEFINED) { |
| 311 | 2357 | return; | |
| 312 | } | ||
| 313 | 3 | const ha_innobase_inplace_ctx *ha_ctx = | |
| 314 | static_cast<const ha_innobase_inplace_ctx *>(ctx); | ||
| 315 | |||
| 316 | /* In InnoDB table, if it's adding AUTOINC column, | ||
| 317 | the sequence value should be shared among contexts */ | ||
| 318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | ut_ad(ha_ctx->add_autoinc != ULINT_UNDEFINED); |
| 319 | 3 | sequence = ha_ctx->sequence; | |
| 320 | } | ||
| 321 | |||
| 322 | private: | ||
| 323 | // Disable copying | ||
| 324 | ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx &); | ||
| 325 | ha_innobase_inplace_ctx &operator=(const ha_innobase_inplace_ctx &); | ||
| 326 | }; | ||
| 327 | |||
| 328 | /** Structure to remember table information for updating DD */ | ||
| 329 | struct alter_table_old_info_t { | ||
| 330 | /** Constructor */ | ||
| 331 | 56562 | alter_table_old_info_t() : m_discarded(), m_fts_doc_id(), m_rebuild() {} | |
| 332 | |||
| 333 | /** If old table is discarded one */ | ||
| 334 | bool m_discarded; | ||
| 335 | |||
| 336 | /** If old table has FTS DOC ID */ | ||
| 337 | bool m_fts_doc_id; | ||
| 338 | |||
| 339 | /** If this ATLER TABLE requires rebuild */ | ||
| 340 | bool m_rebuild; | ||
| 341 | |||
| 342 | /** Update the old table information | ||
| 343 | @param[in] old_table Old InnoDB table object | ||
| 344 | @param[in] rebuild True if rebuild is necessary */ | ||
| 345 | 47397 | void update(const dict_table_t *old_table, bool rebuild) { | |
| 346 | 47397 | m_discarded = dict_table_is_discarded(old_table); | |
| 347 | 47397 | m_fts_doc_id = DICT_TF2_FLAG_IS_SET(old_table, DICT_TF2_FTS_HAS_DOC_ID); | |
| 348 | 47397 | m_rebuild = rebuild; | |
| 349 | 47397 | } | |
| 350 | }; | ||
| 351 | |||
| 352 | /* Report an InnoDB error to the client by invoking my_error(). */ | ||
| 353 | 115 | static UNIV_COLD void my_error_innodb( | |
| 354 | dberr_t error, /*!< in: InnoDB error code */ | ||
| 355 | const char *table, /*!< in: table name */ | ||
| 356 | uint32_t flags) /*!< in: table flags */ | ||
| 357 | { | ||
| 358 |
10/20✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 23 times.
✓ Branch 15 taken 8 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 49 times.
|
115 | switch (error) { |
| 359 | ✗ | case DB_MISSING_HISTORY: | |
| 360 | ✗ | my_error(ER_TABLE_DEF_CHANGED, MYF(0)); | |
| 361 | ✗ | break; | |
| 362 | ✗ | case DB_RECORD_NOT_FOUND: | |
| 363 | ✗ | my_error(ER_KEY_NOT_FOUND, MYF(0), table); | |
| 364 | ✗ | break; | |
| 365 | 1 | case DB_DEADLOCK: | |
| 366 | 1 | my_error(ER_LOCK_DEADLOCK, MYF(0)); | |
| 367 | 1 | break; | |
| 368 | ✗ | case DB_LOCK_WAIT_TIMEOUT: | |
| 369 | ✗ | my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); | |
| 370 | ✗ | break; | |
| 371 | 8 | case DB_INTERRUPTED: | |
| 372 | 8 | my_error(ER_QUERY_INTERRUPTED, MYF(0)); | |
| 373 | 8 | break; | |
| 374 | 16 | case DB_OUT_OF_MEMORY: | |
| 375 | 16 | my_error(ER_OUT_OF_RESOURCES, MYF(0)); | |
| 376 | 16 | break; | |
| 377 | 4 | case DB_OUT_OF_FILE_SPACE: | |
| 378 | 4 | my_error(ER_RECORD_FILE_FULL, MYF(0), table); | |
| 379 | 4 | break; | |
| 380 | ✗ | case DB_OUT_OF_DISK_SPACE: | |
| 381 | ✗ | my_error(ER_DISK_FULL_NOWAIT, MYF(0), table); | |
| 382 | ✗ | break; | |
| 383 | 1 | case DB_TEMP_FILE_WRITE_FAIL: | |
| 384 | 1 | my_error(ER_TEMP_FILE_WRITE_FAILURE, MYF(0)); | |
| 385 | 1 | break; | |
| 386 | ✗ | case DB_TOO_BIG_INDEX_COL: | |
| 387 | ✗ | my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), | |
| 388 | DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags)); | ||
| 389 | ✗ | break; | |
| 390 | 2 | case DB_TOO_MANY_CONCURRENT_TRXS: | |
| 391 | 2 | my_error(ER_TOO_MANY_CONCURRENT_TRXS, MYF(0)); | |
| 392 | 2 | break; | |
| 393 | ✗ | case DB_LOCK_TABLE_FULL: | |
| 394 | ✗ | my_error(ER_LOCK_TABLE_FULL, MYF(0)); | |
| 395 | ✗ | break; | |
| 396 | ✗ | case DB_UNDO_RECORD_TOO_BIG: | |
| 397 | ✗ | my_error(ER_UNDO_RECORD_TOO_BIG, MYF(0)); | |
| 398 | ✗ | break; | |
| 399 | ✗ | case DB_CORRUPTION: | |
| 400 | ✗ | my_error(ER_NOT_KEYFILE, MYF(0), table); | |
| 401 | ✗ | break; | |
| 402 | 23 | case DB_TOO_BIG_RECORD: | |
| 403 | /* We limit max record size to 16k for 64k page size. */ | ||
| 404 | 23 | my_error(ER_TOO_BIG_ROWSIZE, MYF(0), | |
| 405 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | srv_page_size == UNIV_PAGE_SIZE_MAX |
| 406 | ? REC_MAX_DATA_SIZE - 1 | ||
| 407 | 23 | : page_get_free_space_of_empty(flags & DICT_TF_COMPACT) / 2); | |
| 408 | 23 | break; | |
| 409 | 8 | case DB_INVALID_NULL: | |
| 410 | /* TODO: report the row, as we do for DB_DUPLICATE_KEY */ | ||
| 411 | 8 | my_error(ER_INVALID_USE_OF_NULL, MYF(0)); | |
| 412 | 8 | break; | |
| 413 | ✗ | case DB_CANT_CREATE_GEOMETRY_OBJECT: | |
| 414 | ✗ | my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0)); | |
| 415 | ✗ | break; | |
| 416 | 3 | case DB_TABLESPACE_EXISTS: | |
| 417 | 3 | my_error(ER_TABLESPACE_EXISTS, MYF(0), table); | |
| 418 | 3 | break; | |
| 419 | |||
| 420 | #ifdef UNIV_DEBUG | ||
| 421 | ✗ | case DB_SUCCESS: | |
| 422 | case DB_DUPLICATE_KEY: | ||
| 423 | case DB_ONLINE_LOG_TOO_BIG: | ||
| 424 | /* These codes should not be passed here. */ | ||
| 425 | ✗ | ut_error; | |
| 426 | #endif /* UNIV_DEBUG */ | ||
| 427 | 49 | default: | |
| 428 | 49 | my_error(ER_GET_ERRNO, MYF(0), error, "InnoDB error"); | |
| 429 | 49 | break; | |
| 430 | } | ||
| 431 | 115 | } | |
| 432 | |||
| 433 | /** Determine if fulltext indexes exist in a given table. | ||
| 434 | @param table MySQL table | ||
| 435 | @return whether fulltext indexes exist on the table */ | ||
| 436 | 100316 | static bool innobase_fulltext_exist(const TABLE *table) { | |
| 437 |
2/2✓ Branch 0 taken 117285 times.
✓ Branch 1 taken 99080 times.
|
216365 | for (uint i = 0; i < table->s->keys; i++) { |
| 438 |
2/2✓ Branch 0 taken 1236 times.
✓ Branch 1 taken 116049 times.
|
117285 | if (table->key_info[i].flags & HA_FULLTEXT) { |
| 439 | 1236 | return (true); | |
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | 99080 | return (false); | |
| 444 | } | ||
| 445 | |||
| 446 | /** Determine if spatial indexes exist in a given table. | ||
| 447 | @param table MySQL table | ||
| 448 | @return whether spatial indexes exist on the table */ | ||
| 449 | 26679 | static bool innobase_spatial_exist(const TABLE *table) { | |
| 450 |
2/2✓ Branch 0 taken 27446 times.
✓ Branch 1 taken 26641 times.
|
54087 | for (uint i = 0; i < table->s->keys; i++) { |
| 451 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 27408 times.
|
27446 | if (table->key_info[i].flags & HA_SPATIAL) { |
| 452 | 38 | return (true); | |
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | 26641 | return (false); | |
| 457 | } | ||
| 458 | |||
| 459 | /** Get col in new table def of renamed column. | ||
| 460 | @param[in] ha_alter_info inplace alter info | ||
| 461 | @param[in] old_dd_column column in old table | ||
| 462 | @param[in] new_dd_tab new table definition | ||
| 463 | @return column if renamed, NULL otherwise */ | ||
| 464 | ✗ | static dd::Column *get_renamed_col(const Alter_inplace_info *ha_alter_info, | |
| 465 | const dd::Column *old_dd_column, | ||
| 466 | const dd::Table *new_dd_tab) { | ||
| 467 | List_iterator_fast<Create_field> cf_it( | ||
| 468 | ✗ | ha_alter_info->alter_info->create_list); | |
| 469 | ✗ | cf_it.rewind(); | |
| 470 | Create_field *cf; | ||
| 471 | ✗ | while ((cf = cf_it++) != nullptr) { | |
| 472 | ✗ | if (cf->field && cf->field->is_flag_set(FIELD_IS_RENAMED) && | |
| 473 | ✗ | strcmp(cf->change, old_dd_column->name().c_str()) == 0) { | |
| 474 | /* This column is being renamed */ | ||
| 475 | return (const_cast<dd::Column *>( | ||
| 476 | ✗ | dd_find_column(&new_dd_tab->table(), cf->field_name))); | |
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | ✗ | return nullptr; | |
| 481 | } | ||
| 482 | |||
| 483 | /** Copy metadata of dd::Table and dd::Columns from old table to new table. | ||
| 484 | This is done during inplce alter table when table is not rebuilt. | ||
| 485 | @param[in] ha_alter_info inplace alter info | ||
| 486 | @param[in] old_dd_tab old table definition | ||
| 487 | @param[in,out] new_dd_tab new table definition */ | ||
| 488 | 16347 | static void dd_inplace_alter_copy_instant_metadata( | |
| 489 | const Alter_inplace_info *ha_alter_info, const dd::Table *old_dd_tab, | ||
| 490 | dd::Table *new_dd_tab) { | ||
| 491 |
2/2✓ Branch 0 taken 16308 times.
✓ Branch 1 taken 39 times.
|
16347 | if (!dd_table_has_row_versions(*old_dd_tab)) { |
| 492 | 16308 | return; | |
| 493 | } | ||
| 494 | |||
| 495 | /* Copy col phy pos from old DD table to new DD table */ | ||
| 496 |
6/10✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 375 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 375 times.
✓ Branch 9 taken 39 times.
|
414 | for (auto old_dd_column : old_dd_tab->columns()) { |
| 497 | 375 | const char *s = dd_column_key_strings[DD_INSTANT_VERSION_DROPPED]; | |
| 498 |
5/8✓ Branch 0 taken 375 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 375 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 375 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 62 times.
✓ Branch 7 taken 313 times.
|
375 | if (old_dd_column->se_private_data().exists(s)) { |
| 499 | 62 | uint32_t v_dropped = UINT32_UNDEFINED; | |
| 500 |
3/6✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
62 | old_dd_column->se_private_data().get(s, &v_dropped); |
| 501 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | if (v_dropped > 0) { |
| 502 | /* Dropped column will be copied after the loop. Skip for now. */ | ||
| 503 | 62 | continue; | |
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | /* Get corresponding dd::column in new table */ | ||
| 508 | dd::Column *new_dd_column = const_cast<dd::Column *>( | ||
| 509 |
2/4✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
✗ Branch 3 not taken.
|
313 | dd_find_column(new_dd_tab, old_dd_column->name().c_str())); |
| 510 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
|
313 | if (new_dd_column == nullptr) { |
| 511 | /* This column might have been renamed */ | ||
| 512 | ✗ | new_dd_column = get_renamed_col(ha_alter_info, old_dd_column, new_dd_tab); | |
| 513 | } | ||
| 514 | |||
| 515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
|
313 | if (new_dd_column == nullptr) { |
| 516 | /* This column must have been dropped */ | ||
| 517 | ✗ | continue; | |
| 518 | } | ||
| 519 | |||
| 520 |
2/4✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 313 times.
|
313 | if (new_dd_column->is_virtual()) { |
| 521 | ✗ | continue; | |
| 522 | } | ||
| 523 | |||
| 524 | 1356 | auto fn = [&](const char *s, auto &value) { | |
| 525 |
4/6✓ Branch 0 taken 678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 678 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 413 times.
✓ Branch 5 taken 265 times.
|
1356 | if (old_dd_column->se_private_data().exists(s)) { |
| 526 |
2/4✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✗ Branch 3 not taken.
|
826 | old_dd_column->se_private_data().get(s, &value); |
| 527 |
2/4✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 413 times.
✗ Branch 3 not taken.
|
826 | new_dd_column->se_private_data().set(s, value); |
| 528 | } | ||
| 529 | 1669 | }; | |
| 530 | |||
| 531 | /* Copy phy pos for column */ | ||
| 532 | 313 | uint32_t phy_pos = UINT32_UNDEFINED; | |
| 533 | 313 | s = dd_column_key_strings[DD_INSTANT_PHYSICAL_POS]; | |
| 534 |
4/8✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 313 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 313 times.
|
313 | ut_ad(old_dd_column->se_private_data().exists(s)); |
| 535 |
1/2✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
|
313 | fn(s, phy_pos); |
| 536 | |||
| 537 | /* copy version added */ | ||
| 538 | 313 | uint32_t v_added = UINT32_UNDEFINED; | |
| 539 | 313 | s = dd_column_key_strings[DD_INSTANT_VERSION_ADDED]; | |
| 540 |
1/2✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
|
313 | fn(s, v_added); |
| 541 | |||
| 542 | /* Copy instant default values for INSTANT ADD columns */ | ||
| 543 | 313 | s = dd_column_key_strings[DD_INSTANT_COLUMN_DEFAULT_NULL]; | |
| 544 |
5/8✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 313 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 300 times.
|
313 | if (old_dd_column->se_private_data().exists(s)) { |
| 545 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | ut_ad(v_added > 0); |
| 546 | 13 | bool value = false; | |
| 547 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | fn(s, value); |
| 548 | } else { | ||
| 549 | 300 | s = dd_column_key_strings[DD_INSTANT_COLUMN_DEFAULT]; | |
| 550 |
5/8✓ Branch 0 taken 300 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 300 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✓ Branch 7 taken 261 times.
|
300 | if (old_dd_column->se_private_data().exists(s)) { |
| 551 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | ut_ad(v_added > 0); |
| 552 | 39 | dd::String_type value; | |
| 553 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | fn(s, value); |
| 554 | 39 | } else { | |
| 555 | /* This columns is not INSTANT ADD */ | ||
| 556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 261 times.
|
261 | ut_ad(v_added == UINT32_UNDEFINED); |
| 557 | } | ||
| 558 | } | ||
| 559 | } | ||
| 560 | |||
| 561 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 31 times.
|
39 | if (dd_table_has_instant_drop_cols(*old_dd_tab)) { |
| 562 | /* Add INSTANT dropped column from old_dd_tab to new_dd_tab */ | ||
| 563 | 8 | copy_dropped_columns(old_dd_tab, new_dd_tab, UINT32_UNDEFINED); | |
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 567 | /** Check if virtual column in old and new table are in order, excluding | ||
| 568 | those dropped column. This is needed because when we drop a virtual column, | ||
| 569 | ALTER_VIRTUAL_COLUMN_ORDER is also turned on, so we can't decide if this | ||
| 570 | is a real ORDER change or just DROP COLUMN | ||
| 571 | @param[in] table old TABLE | ||
| 572 | @param[in] altered_table new TABLE | ||
| 573 | @param[in] ha_alter_info Structure describing changes to be done | ||
| 574 | by ALTER TABLE and holding data used during in-place alter. | ||
| 575 | @return true is all columns in order, false otherwise. */ | ||
| 576 | 37554 | static bool check_v_col_in_order(const TABLE *table, const TABLE *altered_table, | |
| 577 | const Alter_inplace_info *ha_alter_info) { | ||
| 578 | 37554 | ulint j = 0; | |
| 579 | |||
| 580 | /* We don't support any adding new virtual column before | ||
| 581 | existed virtual column. */ | ||
| 582 |
2/2✓ Branch 0 taken 616 times.
✓ Branch 1 taken 36938 times.
|
37554 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_VIRTUAL_COLUMN) { |
| 583 | 616 | bool has_new = false; | |
| 584 | |||
| 585 | List_iterator_fast<Create_field> cf_it( | ||
| 586 |
1/2✓ Branch 0 taken 616 times.
✗ Branch 1 not taken.
|
616 | ha_alter_info->alter_info->create_list); |
| 587 | |||
| 588 | 616 | cf_it.rewind(); | |
| 589 | |||
| 590 |
2/2✓ Branch 0 taken 2723 times.
✓ Branch 1 taken 609 times.
|
3332 | while (const Create_field *new_field = cf_it++) { |
| 591 |
2/2✓ Branch 0 taken 1677 times.
✓ Branch 1 taken 1046 times.
|
2723 | if (!new_field->is_virtual_gcol()) { |
| 592 | /* We do not support add virtual col | ||
| 593 | before autoinc column */ | ||
| 594 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1675 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
1677 | if (has_new && (new_field->flags & AUTO_INCREMENT_FLAG)) { |
| 595 | 7 | return (false); | |
| 596 | } | ||
| 597 | 1677 | continue; | |
| 598 | } | ||
| 599 | |||
| 600 | /* Found a new added virtual column. */ | ||
| 601 |
2/2✓ Branch 0 taken 656 times.
✓ Branch 1 taken 390 times.
|
1046 | if (!new_field->field) { |
| 602 | 656 | has_new = true; | |
| 603 | 656 | continue; | |
| 604 | } | ||
| 605 | |||
| 606 | /* If there's any old virtual column | ||
| 607 | after the new added virtual column, | ||
| 608 | order must be changed. */ | ||
| 609 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 383 times.
|
390 | if (has_new) { |
| 610 | 7 | return (false); | |
| 611 | } | ||
| 612 | 2716 | } | |
| 613 | } | ||
| 614 | |||
| 615 | /* directly return true if ALTER_VIRTUAL_COLUMN_ORDER is not on */ | ||
| 616 |
2/2✓ Branch 0 taken 37504 times.
✓ Branch 1 taken 43 times.
|
37547 | if (!(ha_alter_info->handler_flags & |
| 617 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) { | ||
| 618 | 37504 | return (true); | |
| 619 | } | ||
| 620 | |||
| 621 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 42 times.
|
398 | for (ulint i = 0; i < table->s->fields; i++) { |
| 622 | 356 | Field *field = table->s->field[i]; | |
| 623 | 356 | bool dropped = false; | |
| 624 | |||
| 625 |
2/2✓ Branch 0 taken 204 times.
✓ Branch 1 taken 152 times.
|
356 | if (field->stored_in_db) { |
| 626 | 204 | continue; | |
| 627 | } | ||
| 628 | |||
| 629 |
3/6✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 152 times.
|
152 | ut_ad(innobase_is_v_fld(field)); |
| 630 | |||
| 631 | /* Check if this column is in drop list */ | ||
| 632 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 109 times.
|
332 | for (const Alter_drop *drop : ha_alter_info->alter_info->drop_list) { |
| 633 |
4/4✓ Branch 0 taken 166 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 180 times.
|
389 | if (drop->type == Alter_drop::COLUMN && |
| 634 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 123 times.
|
166 | my_strcasecmp(system_charset_info, field->field_name, drop->name) == |
| 635 | 0) { | ||
| 636 | 43 | dropped = true; | |
| 637 | 43 | break; | |
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 109 times.
|
152 | if (dropped) { |
| 642 | 43 | continue; | |
| 643 | } | ||
| 644 | |||
| 645 | /* Now check if the next virtual column in altered table | ||
| 646 | matches this column */ | ||
| 647 |
1/2✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
|
284 | while (j < altered_table->s->fields) { |
| 648 | 284 | Field *new_field = altered_table->s->field[j]; | |
| 649 | |||
| 650 |
2/2✓ Branch 0 taken 175 times.
✓ Branch 1 taken 109 times.
|
284 | if (new_field->stored_in_db) { |
| 651 | 175 | j++; | |
| 652 | 175 | continue; | |
| 653 | } | ||
| 654 | |||
| 655 | 109 | if (my_strcasecmp(system_charset_info, field->field_name, | |
| 656 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 108 times.
|
109 | new_field->field_name) != 0) { |
| 657 | /* different column */ | ||
| 658 | 1 | return (false); | |
| 659 | } else { | ||
| 660 | 108 | j++; | |
| 661 | 108 | break; | |
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
|
108 | if (j > altered_table->s->fields) { |
| 666 | /* there should not be less column in new table | ||
| 667 | without them being in drop list */ | ||
| 668 | ✗ | ut_d(ut_error); | |
| 669 | ut_o(return (false)); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | 42 | return (true); | |
| 674 | } | ||
| 675 | |||
| 676 | /** Drop the statistics for a specified table, and mark it as discard | ||
| 677 | after DDL | ||
| 678 | @param[in,out] thd THD object | ||
| 679 | @param[in,out] table InnoDB table object */ | ||
| 680 | 2321 | void innobase_discard_table(THD *thd, dict_table_t *table) { | |
| 681 | char errstr[ERROR_STR_LENGTH]; | ||
| 682 |
2/4✓ Branch 0 taken 2321 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2321 times.
|
2321 | if (dict_stats_drop_table(table->name.m_name, errstr, sizeof(errstr)) != |
| 683 | DB_SUCCESS) { | ||
| 684 | ✗ | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_ALTER_INFO, | |
| 685 | "Deleting persistent statistics" | ||
| 686 | " for table '%s' in" | ||
| 687 | " InnoDB failed: %s", | ||
| 688 | table->name.m_name, errstr); | ||
| 689 | } | ||
| 690 | |||
| 691 | 2321 | table->discard_after_ddl = true; | |
| 692 | 2321 | } | |
| 693 | |||
| 694 | /* To check if renaming a column is ok. | ||
| 695 | @return true if Ok, false otherwise */ | ||
| 696 | 388 | static bool ok_to_rename_column(const Alter_inplace_info *ha_alter_info, | |
| 697 | const TABLE *old_table, | ||
| 698 | const TABLE *altered_table, | ||
| 699 | const dict_table_t *dict_table, bool instant, | ||
| 700 | bool report_error) { | ||
| 701 | List_iterator_fast<Create_field> cf_it( | ||
| 702 |
1/2✓ Branch 0 taken 388 times.
✗ Branch 1 not taken.
|
388 | ha_alter_info->alter_info->create_list); |
| 703 | |||
| 704 |
2/2✓ Branch 0 taken 1251 times.
✓ Branch 1 taken 382 times.
|
1633 | for (Field **fp = old_table->field; *fp; fp++) { |
| 705 |
2/2✓ Branch 0 taken 834 times.
✓ Branch 1 taken 417 times.
|
1251 | if (!(*fp)->is_flag_set(FIELD_IS_RENAMED)) { |
| 706 | 834 | continue; | |
| 707 | } | ||
| 708 | |||
| 709 | 417 | const char *name = nullptr; | |
| 710 | |||
| 711 | 417 | cf_it.rewind(); | |
| 712 |
1/2✓ Branch 0 taken 821 times.
✗ Branch 1 not taken.
|
821 | while (const Create_field *cf = cf_it++) { |
| 713 |
2/2✓ Branch 0 taken 417 times.
✓ Branch 1 taken 404 times.
|
821 | if (cf->field == *fp) { |
| 714 | 417 | name = cf->field_name; | |
| 715 | 417 | goto check_if_ok_to_rename; | |
| 716 | } | ||
| 717 | 404 | } | |
| 718 | |||
| 719 | ✗ | ut_error; | |
| 720 | 417 | check_if_ok_to_rename: | |
| 721 | /* Prohibit renaming a column from FTS_DOC_ID | ||
| 722 | if full-text indexes exist. */ | ||
| 723 |
1/2✓ Branch 0 taken 417 times.
✗ Branch 1 not taken.
|
417 | if (!my_strcasecmp(system_charset_info, (*fp)->field_name, |
| 724 |
6/6✓ Branch 0 taken 5 times.
✓ Branch 1 taken 412 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 415 times.
|
422 | FTS_DOC_ID_COL_NAME) && |
| 725 | 5 | innobase_fulltext_exist(altered_table)) { | |
| 726 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (report_error) { |
| 727 | ✗ | my_error(ER_INNODB_FT_WRONG_DOCID_COLUMN, MYF(0), name); | |
| 728 | } | ||
| 729 | 2 | return false; | |
| 730 | } | ||
| 731 | |||
| 732 | /* Prohibit renaming a column to an internal column. */ | ||
| 733 | 415 | const char *s = dict_table->col_names; | |
| 734 | unsigned j; | ||
| 735 | /* Skip user columns. | ||
| 736 | MySQL should have checked these already. | ||
| 737 | We want to allow renaming of c1 to c2, c2 to c1. */ | ||
| 738 |
2/2✓ Branch 0 taken 1346 times.
✓ Branch 1 taken 415 times.
|
1761 | for (j = 0; j < old_table->s->fields; j++) { |
| 739 |
3/4✓ Branch 0 taken 84 times.
✓ Branch 1 taken 1262 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
|
1346 | if (!innobase_is_v_fld(old_table->field[j])) { |
| 740 | 1262 | s += strlen(s) + 1; | |
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 |
2/2✓ Branch 0 taken 1222 times.
✓ Branch 1 taken 411 times.
|
1633 | for (; j < dict_table->n_def; j++) { |
| 745 |
3/4✓ Branch 0 taken 1222 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1218 times.
|
1222 | if (!my_strcasecmp(system_charset_info, name, s)) { |
| 746 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (report_error) { |
| 747 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_WRONG_COLUMN_NAME, MYF(0), s); |
| 748 | } | ||
| 749 | 4 | return false; | |
| 750 | } | ||
| 751 | |||
| 752 | 1218 | s += strlen(s) + 1; | |
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | /* If column being renamed is being referenced by any other table, don't | ||
| 757 | allow INSTANT in that case. */ | ||
| 758 |
2/2✓ Branch 0 taken 318 times.
✓ Branch 1 taken 64 times.
|
382 | if (instant) { |
| 759 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 299 times.
|
318 | if (!dict_table->referenced_set.empty()) { |
| 760 | List_iterator_fast<Create_field> cf_it( | ||
| 761 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | ha_alter_info->alter_info->create_list); |
| 762 | |||
| 763 |
1/2✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
|
35 | for (Field **fp = old_table->field; *fp; fp++) { |
| 764 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 19 times.
|
35 | if (!(*fp)->is_flag_set(FIELD_IS_RENAMED)) { |
| 765 | 16 | continue; | |
| 766 | } | ||
| 767 | |||
| 768 | 19 | const char *col_name = (*fp)->field_name; | |
| 769 | |||
| 770 | 19 | for (dict_foreign_set::iterator it = dict_table->referenced_set.begin(); | |
| 771 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | it != dict_table->referenced_set.end(); ++it) { |
| 772 | 19 | dict_foreign_t *foreign = *it; | |
| 773 | 19 | const char *r_name = foreign->referenced_col_names[0]; | |
| 774 | |||
| 775 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | for (size_t i = 0; i < foreign->n_fields; ++i) { |
| 776 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | if (!my_strcasecmp(system_charset_info, r_name, col_name)) { |
| 777 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | if (report_error) { |
| 778 | ✗ | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), | |
| 779 | "ALGORITHM=INSTANT", | ||
| 780 | innobase_get_err_msg( | ||
| 781 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME), | ||
| 782 | "ALGORITHM=INPLACE"); | ||
| 783 | } | ||
| 784 | 19 | return false; | |
| 785 | } | ||
| 786 | ✗ | r_name = foreign->referenced_col_names[i]; | |
| 787 | } /* each column in reference element */ | ||
| 788 | } /* each element in reference set */ | ||
| 789 | } /* each column being renamed */ | ||
| 790 | } | ||
| 791 | } | ||
| 792 | |||
| 793 | 363 | return true; | |
| 794 | } | ||
| 795 | |||
| 796 | /** Determine if one ALTER TABLE can be done instantly on the table | ||
| 797 | @param[in] ha_alter_info The DDL operation | ||
| 798 | @param[in] table InnoDB table | ||
| 799 | @param[in] old_table old TABLE | ||
| 800 | @param[in] altered_table new TABLE | ||
| 801 | @return Instant_Type accordingly */ | ||
| 802 | 57575 | static inline Instant_Type innobase_support_instant( | |
| 803 | const Alter_inplace_info *ha_alter_info, const dict_table_t *table, | ||
| 804 | const TABLE *old_table, const TABLE *altered_table) { | ||
| 805 |
2/2✓ Branch 0 taken 6665 times.
✓ Branch 1 taken 50910 times.
|
57575 | if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) { |
| 806 | 6665 | return (Instant_Type::INSTANT_NO_CHANGE); | |
| 807 | } | ||
| 808 | |||
| 809 | 50910 | Alter_inplace_info::HA_ALTER_FLAGS alter_inplace_flags = | |
| 810 | 50910 | ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE; | |
| 811 | |||
| 812 |
2/2✓ Branch 0 taken 36982 times.
✓ Branch 1 taken 13928 times.
|
50910 | if (alter_inplace_flags & ~INNOBASE_INSTANT_ALLOWED) { |
| 813 | 36982 | return (Instant_Type::INSTANT_IMPOSSIBLE); | |
| 814 | } | ||
| 815 | |||
| 816 | /* During upgrade, if columns are added in system tables, avoid instant */ | ||
| 817 |
2/2✓ Branch 0 taken 1875 times.
✓ Branch 1 taken 12053 times.
|
13928 | if (current_thd->is_server_upgrade_thread()) { |
| 818 | 1875 | return (Instant_Type::INSTANT_IMPOSSIBLE); | |
| 819 | } | ||
| 820 | |||
| 821 | enum class INSTANT_OPERATION { | ||
| 822 | COLUMN_RENAME_ONLY, /*!< Only column RENAME */ | ||
| 823 | VIRTUAL_ADD_DROP_ONLY, /*!< Only virtual column ADD AND DROP */ | ||
| 824 | VIRTUAL_ADD_DROP_WITH_RENAME, /*!< Virtual column ADD/DROP with RENAME */ | ||
| 825 | INSTANT_ADD, /*< INSTANT ADD possibly with virtual column ADD and | ||
| 826 | column RENAME */ | ||
| 827 | INSTANT_DROP, /*|< INSTANT DROP possibly with virtual column ADD/DROP and | ||
| 828 | column RENAME */ | ||
| 829 | NONE | ||
| 830 | }; | ||
| 831 | |||
| 832 | 12053 | enum INSTANT_OPERATION op = INSTANT_OPERATION::NONE; | |
| 833 | |||
| 834 |
2/2✓ Branch 0 taken 322 times.
✓ Branch 1 taken 11731 times.
|
12053 | if (!(alter_inplace_flags & ~Alter_inplace_info::ALTER_COLUMN_NAME)) { |
| 835 | 322 | op = INSTANT_OPERATION::COLUMN_RENAME_ONLY; | |
| 836 |
2/2✓ Branch 0 taken 135 times.
✓ Branch 1 taken 11596 times.
|
11731 | } else if (!(alter_inplace_flags & |
| 837 | ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 838 | Alter_inplace_info::DROP_VIRTUAL_COLUMN))) { | ||
| 839 | 135 | op = INSTANT_OPERATION::VIRTUAL_ADD_DROP_ONLY; | |
| 840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11596 times.
|
11596 | } else if (!(alter_inplace_flags & |
| 841 | ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 842 | Alter_inplace_info::DROP_VIRTUAL_COLUMN | | ||
| 843 | Alter_inplace_info::ALTER_COLUMN_NAME))) { | ||
| 844 | ✗ | op = INSTANT_OPERATION::VIRTUAL_ADD_DROP_WITH_RENAME; | |
| 845 |
2/2✓ Branch 0 taken 8973 times.
✓ Branch 1 taken 2623 times.
|
11596 | } else if (alter_inplace_flags & Alter_inplace_info::ADD_STORED_BASE_COLUMN && |
| 846 |
1/2✓ Branch 0 taken 8973 times.
✗ Branch 1 not taken.
|
8973 | !(alter_inplace_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN)) { |
| 847 | 8973 | op = INSTANT_OPERATION::INSTANT_ADD; | |
| 848 |
2/2✓ Branch 0 taken 2574 times.
✓ Branch 1 taken 49 times.
|
2623 | } else if (alter_inplace_flags & Alter_inplace_info::DROP_STORED_COLUMN) { |
| 849 | 2574 | op = INSTANT_OPERATION::INSTANT_DROP; | |
| 850 | } | ||
| 851 | |||
| 852 |
5/7✓ Branch 0 taken 322 times.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2574 times.
✓ Branch 4 taken 8973 times.
✓ Branch 5 taken 49 times.
✗ Branch 6 not taken.
|
12053 | switch (op) { |
| 853 | 322 | case INSTANT_OPERATION::COLUMN_RENAME_ONLY: { | |
| 854 | 322 | bool report_error = (ha_alter_info->alter_info->requested_algorithm == | |
| 855 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT); | ||
| 856 |
2/2✓ Branch 0 taken 299 times.
✓ Branch 1 taken 23 times.
|
322 | if (ok_to_rename_column(ha_alter_info, old_table, altered_table, table, |
| 857 | true, report_error)) { | ||
| 858 | 299 | return (Instant_Type::INSTANT_COLUMN_RENAME); | |
| 859 | } | ||
| 860 | 23 | } break; | |
| 861 | 135 | case INSTANT_OPERATION::VIRTUAL_ADD_DROP_ONLY: | |
| 862 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 1 times.
|
135 | if (check_v_col_in_order(old_table, altered_table, ha_alter_info)) { |
| 863 | 134 | return (Instant_Type::INSTANT_VIRTUAL_ONLY); | |
| 864 | } | ||
| 865 | 1 | break; | |
| 866 | ✗ | case INSTANT_OPERATION::VIRTUAL_ADD_DROP_WITH_RENAME: | |
| 867 | /* Not supported yet in INPLACE. So not supporting here as well. */ | ||
| 868 | ✗ | break; | |
| 869 | 2574 | case INSTANT_OPERATION::INSTANT_DROP: | |
| 870 | /* Disable INSTANT DROP unless explicitly requested. So ALGORITHM=DEFAULT | ||
| 871 | will use INPLACE/COPY */ | ||
| 872 |
2/2✓ Branch 0 taken 1334 times.
✓ Branch 1 taken 1240 times.
|
2574 | if (ha_alter_info->alter_info->requested_algorithm == |
| 873 | Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) { | ||
| 874 | 1334 | break; | |
| 875 | } | ||
| 876 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1240 times.
|
1240 | if (!check_v_col_in_order(old_table, altered_table, ha_alter_info)) { |
| 877 | ✗ | break; | |
| 878 | } | ||
| 879 | [[fallthrough]]; | ||
| 880 | case INSTANT_OPERATION::INSTANT_ADD: | ||
| 881 | |||
| 882 | /* Disable INSTANT DROP unless explicitly requested. So ALGORITHM=DEFAULT | ||
| 883 | will use INPLACE/COPY */ | ||
| 884 |
2/2✓ Branch 0 taken 6590 times.
✓ Branch 1 taken 3623 times.
|
10213 | if (ha_alter_info->alter_info->requested_algorithm == |
| 885 | Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) { | ||
| 886 | 6590 | break; | |
| 887 | } | ||
| 888 | /* If it's an ADD COLUMN without changing existing stored column orders | ||
| 889 | (change trailing virtual column orders is fine, especially for supporting | ||
| 890 | adding stored columns to a table with functional indexes), or including | ||
| 891 | ADD VIRTUAL COLUMN */ | ||
| 892 |
2/2✓ Branch 0 taken 3595 times.
✓ Branch 1 taken 28 times.
|
3623 | if (table->support_instant_add_drop()) { |
| 893 | 3595 | return (Instant_Type::INSTANT_ADD_DROP_COLUMN); | |
| 894 | } | ||
| 895 | 28 | break; | |
| 896 | 49 | case INSTANT_OPERATION::NONE: | |
| 897 | 49 | break; | |
| 898 | } | ||
| 899 | |||
| 900 | 8025 | return (Instant_Type::INSTANT_IMPOSSIBLE); | |
| 901 | } | ||
| 902 | |||
| 903 | /** Determine if this is an instant ALTER TABLE. | ||
| 904 | This can be checked in *inplace_alter_table() functions, which are called | ||
| 905 | after check_if_supported_inplace_alter() | ||
| 906 | @param[in] ha_alter_info The DDL operation | ||
| 907 | @return whether it's an instant ALTER TABLE */ | ||
| 908 | 425816 | static inline bool is_instant(const Alter_inplace_info *ha_alter_info) { | |
| 909 | 425816 | return (ha_alter_info->handler_trivial_ctx != | |
| 910 | 425816 | instant_type_to_int(Instant_Type::INSTANT_IMPOSSIBLE)); | |
| 911 | } | ||
| 912 | |||
| 913 | /** Determine if ALTER TABLE needs to rebuild the table. | ||
| 914 | @param[in] ha_alter_info The DDL operation | ||
| 915 | @param[in] old_table the table we are changing | ||
| 916 | @param[in] is_file_per_table true if table is file_per_table | ||
| 917 | @return whether it is necessary to rebuild the table */ | ||
| 918 | 198007 | [[nodiscard]] static bool innobase_need_rebuild( | |
| 919 | const Alter_inplace_info *ha_alter_info, const TABLE *old_table, | ||
| 920 | bool is_file_per_table) { | ||
| 921 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 197999 times.
|
198007 | if (is_instant(ha_alter_info)) { |
| 922 | 8 | return (false); | |
| 923 | } | ||
| 924 | |||
| 925 | 197999 | Alter_inplace_info::HA_ALTER_FLAGS alter_inplace_flags = | |
| 926 | 197999 | ha_alter_info->handler_flags & ~(INNOBASE_INPLACE_IGNORE); | |
| 927 | |||
| 928 | const bool was_none_explicitly_specified{ | ||
| 929 | 197999 | Encryption::none_explicitly_specified(old_table->s->explicit_encryption, | |
| 930 | 197999 | old_table->s->encrypt_type.str)}; | |
| 931 | |||
| 932 | 197999 | const bool is_none_explicitly_specified{Encryption::none_explicitly_specified( | |
| 933 | 197999 | ha_alter_info->create_info->explicit_encryption, | |
| 934 | 197999 | ha_alter_info->create_info->encrypt_type.str)}; | |
| 935 | |||
| 936 |
4/4✓ Branch 0 taken 11230 times.
✓ Branch 1 taken 120197 times.
✓ Branch 2 taken 2440 times.
✓ Branch 3 taken 8790 times.
|
131427 | if ((!was_none_explicitly_specified && is_none_explicitly_specified && |
| 937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 189209 times.
|
189209 | is_file_per_table) || |
| 938 | 189209 | (Encryption::is_keyring(ha_alter_info->create_info->encrypt_type.str) && | |
| 939 |
4/6✓ Branch 0 taken 131427 times.
✓ Branch 1 taken 66572 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8790 times.
✓ Branch 5 taken 189209 times.
|
395998 | !Encryption::is_keyring(old_table->s->encrypt_type.str)) || |
| 940 | 189209 | ha_alter_info->create_info->encryption_key_id != | |
| 941 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 189209 times.
|
189209 | old_table->s->encryption_key_id) |
| 942 | 8790 | return true; | |
| 943 | |||
| 944 |
2/2✓ Branch 0 taken 92607 times.
✓ Branch 1 taken 96602 times.
|
189209 | if (alter_inplace_flags == Alter_inplace_info::CHANGE_CREATE_OPTION && |
| 945 |
2/2✓ Branch 0 taken 33283 times.
✓ Branch 1 taken 59324 times.
|
92607 | !(ha_alter_info->create_info->used_fields & |
| 946 | (HA_CREATE_USED_ROW_FORMAT | HA_CREATE_USED_KEY_BLOCK_SIZE | | ||
| 947 | HA_CREATE_USED_TABLESPACE))) { | ||
| 948 | /* Any other CHANGE_CREATE_OPTION than changing | ||
| 949 | ROW_FORMAT, KEY_BLOCK_SIZE or TABLESPACE can be done | ||
| 950 | without rebuilding the table. */ | ||
| 951 | 33283 | return (false); | |
| 952 | } | ||
| 953 | |||
| 954 | 155926 | return (!!(ha_alter_info->handler_flags & INNOBASE_ALTER_REBUILD)); | |
| 955 | } | ||
| 956 | |||
| 957 | /** Check if InnoDB supports a particular alter table in-place | ||
| 958 | @param altered_table TABLE object for new version of table. | ||
| 959 | @param ha_alter_info Structure describing changes to be done | ||
| 960 | by ALTER TABLE and holding data used during in-place alter. | ||
| 961 | |||
| 962 | @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported | ||
| 963 | @retval HA_ALTER_INPLACE_NO_LOCK Supported | ||
| 964 | @retval HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE Supported, but requires | ||
| 965 | lock during main phase and exclusive lock during prepare phase. | ||
| 966 | @retval HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE Supported, prepare phase | ||
| 967 | requires exclusive lock (any transactions that have accessed the table | ||
| 968 | must commit or roll back first, and no transactions can access the table | ||
| 969 | while prepare_inplace_alter_table() is executing) | ||
| 970 | */ | ||
| 971 | 57699 | enum_alter_inplace_result ha_innobase::check_if_supported_inplace_alter( | |
| 972 | TABLE *altered_table, Alter_inplace_info *ha_alter_info) { | ||
| 973 |
1/2✓ Branch 0 taken 57699 times.
✗ Branch 1 not taken.
|
57699 | DBUG_TRACE; |
| 974 | |||
| 975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57699 times.
|
57699 | if (srv_sys_space.created_new_raw()) { |
| 976 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 977 | } | ||
| 978 | |||
| 979 |
3/4✓ Branch 0 taken 57687 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57687 times.
|
57699 | if (high_level_read_only || srv_force_recovery) { |
| 980 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (srv_force_recovery) { |
| 981 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_INNODB_FORCED_RECOVERY, MYF(0)); |
| 982 | } else { | ||
| 983 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_READ_ONLY_MODE, MYF(0)); |
| 984 | } | ||
| 985 | 12 | return HA_ALTER_ERROR; | |
| 986 | } | ||
| 987 | |||
| 988 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 57679 times.
|
57687 | if (altered_table->s->fields > REC_MAX_N_USER_FIELDS) { |
| 989 | /* Deny the inplace ALTER TABLE. MySQL will try to | ||
| 990 | re-create the table and ha_innobase::create() will | ||
| 991 | return an error too. This is how we effectively | ||
| 992 | deny adding too many columns to a table. */ | ||
| 993 | 8 | ha_alter_info->unsupported_reason = | |
| 994 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | innobase_get_err_msg(ER_TOO_MANY_FIELDS); |
| 995 | 8 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 996 | } | ||
| 997 | |||
| 998 | /* We don't support change Master key encryption attribute with | ||
| 999 | inplace algorithm. */ | ||
| 1000 | 57679 | char *old_encryption = this->table->s->encrypt_type.str; | |
| 1001 | 57679 | char *new_encryption = altered_table->s->encrypt_type.str; | |
| 1002 | |||
| 1003 |
2/2✓ Branch 0 taken 358 times.
✓ Branch 1 taken 57321 times.
|
115358 | if (Encryption::is_master_key_encryption(old_encryption) != |
| 1004 | 57679 | Encryption::is_master_key_encryption(new_encryption)) { | |
| 1005 | 358 | ha_alter_info->unsupported_reason = | |
| 1006 |
1/2✓ Branch 0 taken 358 times.
✗ Branch 1 not taken.
|
358 | innobase_get_err_msg(ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE); |
| 1007 | 358 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1008 | } | ||
| 1009 | |||
| 1010 |
1/2✓ Branch 0 taken 57321 times.
✗ Branch 1 not taken.
|
57321 | update_thd(); |
| 1011 | |||
| 1012 |
2/2✓ Branch 0 taken 3586 times.
✓ Branch 1 taken 53735 times.
|
57321 | if (ha_alter_info->handler_flags & |
| 1013 | ~(INNOBASE_INPLACE_IGNORE | INNOBASE_ALTER_NOREBUILD | | ||
| 1014 | INNOBASE_ALTER_REBUILD)) { | ||
| 1015 |
2/2✓ Branch 0 taken 3450 times.
✓ Branch 1 taken 136 times.
|
3586 | if (ha_alter_info->handler_flags & |
| 1016 | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) { | ||
| 1017 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3440 times.
|
3450 | if (ha_alter_info->alter_info->requested_algorithm == |
| 1018 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 1019 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | ha_alter_info->unsupported_reason = innobase_get_err_msg( |
| 1020 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE_INSTANT); | ||
| 1021 | } else { | ||
| 1022 |
1/2✓ Branch 0 taken 3440 times.
✗ Branch 1 not taken.
|
3440 | ha_alter_info->unsupported_reason = innobase_get_err_msg( |
| 1023 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE); | ||
| 1024 | } | ||
| 1025 | } | ||
| 1026 | 3586 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1027 | } | ||
| 1028 | |||
| 1029 | /* Only support online add foreign key constraint when check_foreigns is | ||
| 1030 | turned off */ | ||
| 1031 |
2/2✓ Branch 0 taken 170 times.
✓ Branch 1 taken 53565 times.
|
53735 | if ((ha_alter_info->handler_flags & Alter_inplace_info::ADD_FOREIGN_KEY) && |
| 1032 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 96 times.
|
170 | m_prebuilt->trx->check_foreigns) { |
| 1033 | 74 | ha_alter_info->unsupported_reason = | |
| 1034 |
1/2✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
|
74 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK); |
| 1035 | 74 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1036 | } | ||
| 1037 | |||
| 1038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53661 times.
|
53661 | if (altered_table->file->ht != ht) { |
| 1039 | /* Non-native partitioning table engine. No longer supported, due to | ||
| 1040 | implementation of native InnoDB partitioning. */ | ||
| 1041 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1042 | } | ||
| 1043 | |||
| 1044 | 107322 | Instant_Type instant_type = innobase_support_instant( | |
| 1045 |
1/2✓ Branch 0 taken 53661 times.
✗ Branch 1 not taken.
|
53661 | ha_alter_info, m_prebuilt->table, this->table, altered_table); |
| 1046 | |||
| 1047 | 53661 | ha_alter_info->handler_trivial_ctx = | |
| 1048 | 53661 | instant_type_to_int(Instant_Type::INSTANT_IMPOSSIBLE); | |
| 1049 | |||
| 1050 |
3/4✓ Branch 0 taken 53661 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52860 times.
✓ Branch 3 taken 801 times.
|
53661 | if (!dict_table_is_partition(m_prebuilt->table)) { |
| 1051 |
3/4✓ Branch 0 taken 45243 times.
✓ Branch 1 taken 747 times.
✓ Branch 2 taken 6870 times.
✗ Branch 3 not taken.
|
52860 | switch (instant_type) { |
| 1052 | 45243 | case Instant_Type::INSTANT_IMPOSSIBLE: | |
| 1053 | 45243 | break; | |
| 1054 | 747 | case Instant_Type::INSTANT_ADD_DROP_COLUMN: | |
| 1055 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 679 times.
|
747 | if (ha_alter_info->alter_info->requested_algorithm == |
| 1056 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE) { | ||
| 1057 | /* Still fall back to INPLACE since the behaviour is different */ | ||
| 1058 | 68 | break; | |
| 1059 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 679 times.
|
679 | } else if (m_prebuilt->table->n_def == REC_MAX_N_FIELDS) { |
| 1060 | ✗ | if (ha_alter_info->alter_info->requested_algorithm == | |
| 1061 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 1062 | ✗ | my_error(ER_TOO_MANY_FIELDS, MYF(0), | |
| 1063 | ✗ | m_prebuilt->table->name.m_name); | |
| 1064 | ✗ | return HA_ALTER_ERROR; | |
| 1065 | } | ||
| 1066 | /* INSTANT can't be done any more. Fall back to INPLACE. */ | ||
| 1067 | ✗ | break; | |
| 1068 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 677 times.
|
679 | } else if (m_prebuilt->table->current_row_version == MAX_ROW_VERSION) { |
| 1069 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (ha_alter_info->alter_info->requested_algorithm == |
| 1070 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 1071 | 2 | my_error(ER_INNODB_MAX_ROW_VERSION, MYF(0), | |
| 1072 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | m_prebuilt->table->name.m_name); |
| 1073 | 2 | return HA_ALTER_ERROR; | |
| 1074 | } | ||
| 1075 | |||
| 1076 | /* INSTANT can't be done any more. Fall back to INPLACE. */ | ||
| 1077 | ✗ | break; | |
| 1078 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 673 times.
|
677 | } else if (!Instant_ddl_impl<dd::Table>::is_instant_add_possible( |
| 1079 | 677 | ha_alter_info, table, altered_table, | |
| 1080 |
1/2✓ Branch 0 taken 677 times.
✗ Branch 1 not taken.
|
677 | m_prebuilt->table)) { |
| 1081 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (ha_alter_info->alter_info->requested_algorithm == |
| 1082 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 1083 | /* Try to find if after adding columns, any possible row stays | ||
| 1084 | within permissible limit. If it doesn't, return error. */ | ||
| 1085 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_INNODB_INSTANT_ADD_NOT_SUPPORTED_MAX_SIZE, MYF(0)); |
| 1086 | 4 | return HA_ALTER_ERROR; | |
| 1087 | } | ||
| 1088 | |||
| 1089 | /* INSTANT can't be done. Fall back to INPLACE. */ | ||
| 1090 | ✗ | break; | |
| 1091 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 665 times.
|
673 | } else if (ha_alter_info->error_if_not_empty) { |
| 1092 | /* In this case, it can't be instant because the table | ||
| 1093 | may not be empty. Have to fall back to INPLACE */ | ||
| 1094 | 8 | break; | |
| 1095 | } | ||
| 1096 | [[fallthrough]]; | ||
| 1097 | case Instant_Type::INSTANT_NO_CHANGE: | ||
| 1098 | case Instant_Type::INSTANT_VIRTUAL_ONLY: | ||
| 1099 | case Instant_Type::INSTANT_COLUMN_RENAME: | ||
| 1100 | 7535 | ha_alter_info->handler_trivial_ctx = instant_type_to_int(instant_type); | |
| 1101 | 7535 | return HA_ALTER_INPLACE_INSTANT; | |
| 1102 | } | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | /* Only support NULL -> NOT NULL change if strict table sql_mode | ||
| 1106 | is set. Fall back to COPY for conversion if not strict tables. | ||
| 1107 | In-Place will fail with an error when trying to convert | ||
| 1108 | NULL to a NOT NULL value. */ | ||
| 1109 | 92240 | if ((ha_alter_info->handler_flags & | |
| 1110 |
4/4✓ Branch 0 taken 248 times.
✓ Branch 1 taken 45872 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 46047 times.
|
46368 | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) && |
| 1111 |
3/4✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 175 times.
|
248 | !thd_is_strict_mode(m_user_thd)) { |
| 1112 | 73 | ha_alter_info->unsupported_reason = | |
| 1113 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL); |
| 1114 | 73 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1115 | } | ||
| 1116 | |||
| 1117 | /* DROP PRIMARY KEY is only allowed in combination with ADD | ||
| 1118 | PRIMARY KEY. */ | ||
| 1119 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 45926 times.
|
46047 | if ((ha_alter_info->handler_flags & (Alter_inplace_info::ADD_PK_INDEX | |
| 1120 | Alter_inplace_info::DROP_PK_INDEX)) == | ||
| 1121 | Alter_inplace_info::DROP_PK_INDEX) { | ||
| 1122 | 121 | ha_alter_info->unsupported_reason = | |
| 1123 |
1/2✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
|
121 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK); |
| 1124 | 121 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1125 | } | ||
| 1126 | |||
| 1127 | /* If a column change from NOT NULL to NULL, | ||
| 1128 | and there's a implict pk on this column. the | ||
| 1129 | table should be rebuild. The change should | ||
| 1130 | only go through the "Copy" method. */ | ||
| 1131 |
2/2✓ Branch 0 taken 196 times.
✓ Branch 1 taken 45730 times.
|
45926 | if ((ha_alter_info->handler_flags & |
| 1132 | Alter_inplace_info::ALTER_COLUMN_NULLABLE)) { | ||
| 1133 | 196 | const uint my_primary_key = altered_table->s->primary_key; | |
| 1134 | |||
| 1135 | /* See if MYSQL table has no pk but we do. */ | ||
| 1136 |
3/4✓ Branch 0 taken 73 times.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 196 times.
|
269 | if (UNIV_UNLIKELY(my_primary_key >= MAX_KEY) && |
| 1137 |
2/4✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
|
73 | !row_table_got_default_clust_index(m_prebuilt->table)) { |
| 1138 | ✗ | ha_alter_info->unsupported_reason = | |
| 1139 | ✗ | innobase_get_err_msg(ER_PRIMARY_CANT_HAVE_NULL); | |
| 1140 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1141 | } | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | 45926 | bool add_drop_v_cols = false; | |
| 1145 | |||
| 1146 | /* If there is add or drop virtual columns, we will support operations | ||
| 1147 | with these 3 options alone with inplace interface for now */ | ||
| 1148 |
2/2✓ Branch 0 taken 790 times.
✓ Branch 1 taken 45136 times.
|
45926 | if (ha_alter_info->handler_flags & |
| 1149 | (Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 1150 | Alter_inplace_info::DROP_VIRTUAL_COLUMN | | ||
| 1151 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) { | ||
| 1152 | 790 | ulonglong flags = ha_alter_info->handler_flags; | |
| 1153 | |||
| 1154 | /* TODO: uncomment the flags below, once we start to | ||
| 1155 | support them */ | ||
| 1156 | 790 | flags &= | |
| 1157 | ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 1158 | Alter_inplace_info::DROP_VIRTUAL_COLUMN | | ||
| 1159 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER | ||
| 1160 | /* | ||
| 1161 | | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | ||
| 1162 | | Alter_inplace_info::ADD_STORED_BASE_COLUMN | ||
| 1163 | | Alter_inplace_info::DROP_STORED_COLUMN | ||
| 1164 | | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | ||
| 1165 | | Alter_inplace_info::ADD_UNIQUE_INDEX | ||
| 1166 | */ | ||
| 1167 | | Alter_inplace_info::ADD_INDEX | Alter_inplace_info::DROP_INDEX); | ||
| 1168 | |||
| 1169 | 1209 | if (flags != 0 || | |
| 1170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 419 times.
|
419 | (altered_table->s->partition_info_str && |
| 1171 |
4/6✓ Branch 0 taken 419 times.
✓ Branch 1 taken 371 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 378 times.
✓ Branch 5 taken 412 times.
|
1209 | altered_table->s->partition_info_str_len) || |
| 1172 |
3/4✓ Branch 0 taken 419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 412 times.
|
419 | (!check_v_col_in_order(this->table, altered_table, ha_alter_info))) { |
| 1173 | 378 | ha_alter_info->unsupported_reason = | |
| 1174 |
1/2✓ Branch 0 taken 378 times.
✗ Branch 1 not taken.
|
378 | innobase_get_err_msg(ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); |
| 1175 | 378 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1176 | } | ||
| 1177 | |||
| 1178 | 412 | add_drop_v_cols = true; | |
| 1179 | } | ||
| 1180 | |||
| 1181 | /* We should be able to do the operation in-place. | ||
| 1182 | See if we can do it online (LOCK=NONE). */ | ||
| 1183 | 45548 | bool online = true; | |
| 1184 | |||
| 1185 | List_iterator_fast<Create_field> cf_it( | ||
| 1186 |
1/2✓ Branch 0 taken 45548 times.
✗ Branch 1 not taken.
|
45548 | ha_alter_info->alter_info->create_list); |
| 1187 | |||
| 1188 | /* Fix the key parts. */ | ||
| 1189 | 93812 | for (KEY *new_key = ha_alter_info->key_info_buffer; | |
| 1190 |
2/2✓ Branch 0 taken 48265 times.
✓ Branch 1 taken 45547 times.
|
93812 | new_key < ha_alter_info->key_info_buffer + ha_alter_info->key_count; |
| 1191 | new_key++) { | ||
| 1192 | /* Do not support adding/dropping a virtual column, while | ||
| 1193 | there is a table rebuild caused by adding a new FTS_DOC_ID */ | ||
| 1194 |
4/6✓ Branch 0 taken 1524 times.
✓ Branch 1 taken 46741 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1524 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 48265 times.
|
48265 | if ((new_key->flags & HA_FULLTEXT) && add_drop_v_cols && |
| 1195 | ✗ | !DICT_TF2_FLAG_IS_SET(m_prebuilt->table, DICT_TF2_FTS_HAS_DOC_ID)) { | |
| 1196 | ✗ | ha_alter_info->unsupported_reason = | |
| 1197 | ✗ | innobase_get_err_msg(ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); | |
| 1198 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1199 | } | ||
| 1200 | |||
| 1201 | 122496 | for (KEY_PART_INFO *key_part = new_key->key_part; | |
| 1202 |
2/2✓ Branch 0 taken 74232 times.
✓ Branch 1 taken 48264 times.
|
122496 | key_part < new_key->key_part + new_key->user_defined_key_parts; |
| 1203 | key_part++) { | ||
| 1204 | 74232 | const Create_field *new_field = nullptr; | |
| 1205 | |||
| 1206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74232 times.
|
74232 | assert(key_part->fieldnr < altered_table->s->fields); |
| 1207 | |||
| 1208 | 74232 | cf_it.rewind(); | |
| 1209 |
2/2✓ Branch 0 taken 222345 times.
✓ Branch 1 taken 74232 times.
|
296577 | for (auto fieldnr = 0; fieldnr != key_part->fieldnr + 1; fieldnr++) { |
| 1210 | 222345 | new_field = cf_it++; | |
| 1211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 222345 times.
|
222345 | assert(new_field); |
| 1212 | } | ||
| 1213 | |||
| 1214 | 74232 | key_part->field = altered_table->field[key_part->fieldnr]; | |
| 1215 | /* In some special cases InnoDB emits "false" | ||
| 1216 | duplicate key errors with NULL key values. Let | ||
| 1217 | us play safe and ensure that we can correctly | ||
| 1218 | print key values even in such cases. */ | ||
| 1219 |
1/2✓ Branch 0 taken 74232 times.
✗ Branch 1 not taken.
|
74232 | key_part->null_offset = key_part->field->null_offset(); |
| 1220 | 74232 | key_part->null_bit = key_part->field->null_bit; | |
| 1221 | |||
| 1222 |
2/2✓ Branch 0 taken 73919 times.
✓ Branch 1 taken 313 times.
|
74232 | if (new_field->field) { |
| 1223 | /* This is an existing column. */ | ||
| 1224 | 73919 | continue; | |
| 1225 | } | ||
| 1226 | |||
| 1227 | /* This is an added column. */ | ||
| 1228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
|
313 | assert(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN); |
| 1229 | |||
| 1230 | /* We cannot replace a hidden FTS_DOC_ID | ||
| 1231 | with a user-visible FTS_DOC_ID. */ | ||
| 1232 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 312 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 313 times.
|
314 | if (m_prebuilt->table->fts && innobase_fulltext_exist(altered_table) && |
| 1233 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | !my_strcasecmp(system_charset_info, key_part->field->field_name, |
| 1234 | FTS_DOC_ID_COL_NAME)) { | ||
| 1235 | ✗ | ha_alter_info->unsupported_reason = innobase_get_err_msg( | |
| 1236 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS); | ||
| 1237 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1238 | } | ||
| 1239 | |||
| 1240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
|
313 | assert(((key_part->field->auto_flags & Field::NEXT_NUMBER) != 0) == |
| 1241 | key_part->field->is_flag_set(AUTO_INCREMENT_FLAG)); | ||
| 1242 | |||
| 1243 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 270 times.
|
313 | if (key_part->field->is_flag_set(AUTO_INCREMENT_FLAG)) { |
| 1244 | /* We cannot assign an AUTO_INCREMENT | ||
| 1245 | column values during online ALTER. */ | ||
| 1246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | assert(key_part->field == altered_table->found_next_number_field); |
| 1247 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | ha_alter_info->unsupported_reason = innobase_get_err_msg( |
| 1248 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC); | ||
| 1249 | 43 | online = false; | |
| 1250 | } | ||
| 1251 | |||
| 1252 |
2/2✓ Branch 0 taken 183 times.
✓ Branch 1 taken 130 times.
|
313 | if (key_part->field->is_virtual_gcol()) { |
| 1253 | /* Do not support adding index on newly added | ||
| 1254 | virtual column, while there is also a drop | ||
| 1255 | virtual column in the same clause */ | ||
| 1256 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 182 times.
|
183 | if (ha_alter_info->handler_flags & |
| 1257 | Alter_inplace_info::DROP_VIRTUAL_COLUMN) { | ||
| 1258 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | ha_alter_info->unsupported_reason = innobase_get_err_msg( |
| 1259 | ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); | ||
| 1260 | |||
| 1261 | 1 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1262 | } | ||
| 1263 | |||
| 1264 | 182 | ha_alter_info->unsupported_reason = | |
| 1265 |
1/2✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
|
182 | innobase_get_err_msg(ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN); |
| 1266 | 182 | online = false; | |
| 1267 | } | ||
| 1268 | } | ||
| 1269 | } | ||
| 1270 | |||
| 1271 |
3/4✓ Branch 0 taken 535 times.
✓ Branch 1 taken 45012 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 535 times.
|
45547 | assert(!m_prebuilt->table->fts || |
| 1272 | m_prebuilt->table->fts->doc_col <= table->s->fields); | ||
| 1273 |
4/6✓ Branch 0 taken 535 times.
✓ Branch 1 taken 45012 times.
✓ Branch 2 taken 535 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 535 times.
|
45547 | assert(!m_prebuilt->table->fts || m_prebuilt->table->fts->doc_col < |
| 1274 | m_prebuilt->table->get_n_user_cols()); | ||
| 1275 | |||
| 1276 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 45464 times.
|
45547 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_SPATIAL_INDEX) { |
| 1277 | 83 | ha_alter_info->unsupported_reason = | |
| 1278 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); |
| 1279 | 83 | online = false; | |
| 1280 | } | ||
| 1281 | |||
| 1282 |
6/6✓ Branch 0 taken 535 times.
✓ Branch 1 taken 45012 times.
✓ Branch 2 taken 397 times.
✓ Branch 3 taken 138 times.
✓ Branch 4 taken 397 times.
✓ Branch 5 taken 45150 times.
|
45547 | if (m_prebuilt->table->fts && innobase_fulltext_exist(altered_table)) { |
| 1283 | /* FULLTEXT indexes are supposed to remain. */ | ||
| 1284 | /* Disallow DROP INDEX FTS_DOC_ID_INDEX */ | ||
| 1285 | |||
| 1286 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 397 times.
|
418 | for (uint i = 0; i < ha_alter_info->index_drop_count; i++) { |
| 1287 |
2/4✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
|
21 | if (!my_strcasecmp(system_charset_info, |
| 1288 | ha_alter_info->index_drop_buffer[i]->name, | ||
| 1289 | FTS_DOC_ID_INDEX_NAME)) { | ||
| 1290 | ✗ | ha_alter_info->unsupported_reason = innobase_get_err_msg( | |
| 1291 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS); | ||
| 1292 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1293 | } | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | /* InnoDB can have a hidden FTS_DOC_ID_INDEX on a | ||
| 1297 | visible FTS_DOC_ID column as well. Prevent dropping or | ||
| 1298 | renaming the FTS_DOC_ID. */ | ||
| 1299 | |||
| 1300 |
2/2✓ Branch 0 taken 2558 times.
✓ Branch 1 taken 392 times.
|
2950 | for (Field **fp = table->field; *fp; fp++) { |
| 1301 |
4/4✓ Branch 0 taken 2552 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2547 times.
✓ Branch 3 taken 11 times.
|
5110 | if (!((*fp)->is_flag_set(FIELD_IS_RENAMED) || |
| 1302 |
2/2✓ Branch 0 taken 2547 times.
✓ Branch 1 taken 5 times.
|
2552 | (*fp)->is_flag_set(FIELD_IS_DROPPED))) { |
| 1303 | 2547 | continue; | |
| 1304 | } | ||
| 1305 | |||
| 1306 |
3/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 6 times.
|
11 | if (!my_strcasecmp(system_charset_info, (*fp)->field_name, |
| 1307 | FTS_DOC_ID_COL_NAME)) { | ||
| 1308 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | ha_alter_info->unsupported_reason = innobase_get_err_msg( |
| 1309 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS); | ||
| 1310 | 5 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1311 | } | ||
| 1312 | } | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | 45542 | m_prebuilt->trx->will_lock++; | |
| 1316 | |||
| 1317 |
2/2✓ Branch 0 taken 45250 times.
✓ Branch 1 taken 292 times.
|
45542 | if (!online) { |
| 1318 | /* We already determined that only a non-locking | ||
| 1319 | operation is possible. */ | ||
| 1320 | 90500 | } else if (((ha_alter_info->handler_flags & | |
| 1321 |
2/2✓ Branch 0 taken 25096 times.
✓ Branch 1 taken 18564 times.
|
43660 | Alter_inplace_info::ADD_PK_INDEX) || |
| 1322 | 43660 | innobase_need_rebuild( | |
| 1323 | ha_alter_info, altered_table, | ||
| 1324 |
7/8✓ Branch 0 taken 43660 times.
✓ Branch 1 taken 1590 times.
✓ Branch 2 taken 43660 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26656 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 49 times.
✓ Branch 7 taken 45201 times.
|
117156 | dict_table_is_file_per_table(m_prebuilt->table))) && |
| 1325 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 26637 times.
|
53342 | (innobase_fulltext_exist(altered_table) || |
| 1326 | 26656 | innobase_spatial_exist(altered_table))) { | |
| 1327 | /* Refuse to rebuild the table online, if | ||
| 1328 | FULLTEXT OR SPATIAL indexes are to survive the rebuild. */ | ||
| 1329 | 49 | online = false; | |
| 1330 | /* If the table already contains fulltext indexes, | ||
| 1331 | refuse to rebuild the table natively altogether. */ | ||
| 1332 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 23 times.
|
49 | if (m_prebuilt->table->fts) { |
| 1333 | 26 | ha_alter_info->unsupported_reason = | |
| 1334 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | innobase_get_err_msg(ER_INNODB_FT_LIMIT); |
| 1335 | 26 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 1336 | } | ||
| 1337 | |||
| 1338 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (innobase_spatial_exist(altered_table)) { |
| 1339 | 19 | ha_alter_info->unsupported_reason = | |
| 1340 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); |
| 1341 | } else { | ||
| 1342 | 4 | ha_alter_info->unsupported_reason = | |
| 1343 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); |
| 1344 | } | ||
| 1345 |
2/2✓ Branch 0 taken 4932 times.
✓ Branch 1 taken 40269 times.
|
45201 | } else if ((ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX)) { |
| 1346 | /* Building a full-text index requires a lock. | ||
| 1347 | We could do without a lock if the table already contains | ||
| 1348 | an FTS_DOC_ID column, but in that case we would have | ||
| 1349 | to apply the modification log to the full-text indexes. */ | ||
| 1350 | |||
| 1351 |
2/2✓ Branch 0 taken 5171 times.
✓ Branch 1 taken 4464 times.
|
9635 | for (uint i = 0; i < ha_alter_info->index_add_count; i++) { |
| 1352 | 5171 | const KEY *key = | |
| 1353 | 5171 | &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; | |
| 1354 |
2/2✓ Branch 0 taken 468 times.
✓ Branch 1 taken 4703 times.
|
5171 | if (key->flags & HA_FULLTEXT) { |
| 1355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 468 times.
|
468 | assert(!(key->flags & HA_KEYFLAG_MASK & |
| 1356 | ~(HA_FULLTEXT | HA_PACK_KEY | HA_GENERATED_KEY | | ||
| 1357 | HA_BINARY_PACK_KEY))); | ||
| 1358 | 468 | ha_alter_info->unsupported_reason = | |
| 1359 |
1/2✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
|
468 | innobase_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); |
| 1360 | 468 | online = false; | |
| 1361 | 468 | break; | |
| 1362 | } | ||
| 1363 | } | ||
| 1364 | } | ||
| 1365 | |||
| 1366 |
2/2✓ Branch 0 taken 44733 times.
✓ Branch 1 taken 783 times.
|
45516 | return online ? HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE |
| 1367 | 45516 | : HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE; | |
| 1368 | 57699 | } | |
| 1369 | |||
| 1370 | /** Update the metadata in prepare phase. This only check if dd::Tablespace | ||
| 1371 | should be removed or(and) created, because to remove and store dd::Tablespace | ||
| 1372 | could fail, so it's better to do it earlier, to prevent a late rollback | ||
| 1373 | @param[in,out] thd MySQL connection | ||
| 1374 | @param[in] old_table Old InnoDB table object | ||
| 1375 | @param[in,out] new_table New InnoDB table object | ||
| 1376 | @param[in] old_dd_tab Old dd::Table or dd::Partition | ||
| 1377 | @return false On success | ||
| 1378 | @retval true On failure */ | ||
| 1379 | template <typename Table> | ||
| 1380 | [[nodiscard]] static bool dd_prepare_inplace_alter_table( | ||
| 1381 | THD *thd, const dict_table_t *old_table, dict_table_t *new_table, | ||
| 1382 | const Table *old_dd_tab); | ||
| 1383 | |||
| 1384 | /** Update metadata in commit phase. Note this function should only update | ||
| 1385 | the metadata which would not result in failure | ||
| 1386 | @param[in] old_info Some table information for the old table | ||
| 1387 | @param[in,out] new_table New InnoDB table object | ||
| 1388 | @param[in] old_dd_tab Old dd::Table or dd::Partition | ||
| 1389 | @param[in,out] new_dd_tab New dd::Table or dd::Partition */ | ||
| 1390 | template <typename Table> | ||
| 1391 | static void dd_commit_inplace_alter_table( | ||
| 1392 | const alter_table_old_info_t &old_info, dict_table_t *new_table, | ||
| 1393 | const Table *old_dd_tab, Table *new_dd_tab); | ||
| 1394 | |||
| 1395 | /** Update metadata in commit phase when the alter table does | ||
| 1396 | no change to the table | ||
| 1397 | @param[in] ha_alter_info the DDL operation | ||
| 1398 | @param[in] old_dd_tab Old dd::Table or dd::Partition | ||
| 1399 | @param[in] new_dd_tab New dd::Table or dd::Partition | ||
| 1400 | @param[in] ignore_fts ignore FTS update if true */ | ||
| 1401 | template <typename Table> | ||
| 1402 | static void dd_commit_inplace_no_change(const Alter_inplace_info *ha_alter_info, | ||
| 1403 | const Table *old_dd_tab, | ||
| 1404 | Table *new_dd_tab, bool ignore_fts); | ||
| 1405 | |||
| 1406 | /** Update table level instant metadata in commit phase | ||
| 1407 | @param[in] table InnoDB table object | ||
| 1408 | @param[in] old_dd_tab old dd::Table | ||
| 1409 | @param[in] new_dd_tab new dd::Table */ | ||
| 1410 | static void dd_commit_inplace_update_instant_meta(const dict_table_t *table, | ||
| 1411 | const dd::Table *old_dd_tab, | ||
| 1412 | dd::Table *new_dd_tab); | ||
| 1413 | |||
| 1414 | /** Allows InnoDB to update internal structures with concurrent | ||
| 1415 | writes blocked (provided that check_if_supported_inplace_alter() | ||
| 1416 | did not return HA_ALTER_INPLACE_NO_LOCK). | ||
| 1417 | This will be invoked before inplace_alter_table(). | ||
| 1418 | @param[in] altered_table TABLE object for new version of table. | ||
| 1419 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 1420 | by ALTER TABLE and holding data used during in-place alter. | ||
| 1421 | @param[in] old_dd_tab dd::Table object describing old version | ||
| 1422 | of the table. | ||
| 1423 | @param[in,out] new_dd_tab dd::Table object for the new version of | ||
| 1424 | the table. Can be adjusted by this call. Changes to the table definition will | ||
| 1425 | be persisted in the data-dictionary at statement commit time. | ||
| 1426 | @retval true Failure | ||
| 1427 | @retval false Success | ||
| 1428 | */ | ||
| 1429 | 52196 | bool ha_innobase::prepare_inplace_alter_table(TABLE *altered_table, | |
| 1430 | Alter_inplace_info *ha_alter_info, | ||
| 1431 | const dd::Table *old_dd_tab, | ||
| 1432 | dd::Table *new_dd_tab) { | ||
| 1433 |
1/2✓ Branch 0 taken 52196 times.
✗ Branch 1 not taken.
|
52196 | DBUG_TRACE; |
| 1434 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52196 times.
|
52196 | ut_ad(old_dd_tab != nullptr); |
| 1435 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52196 times.
|
52196 | ut_ad(new_dd_tab != nullptr); |
| 1436 | |||
| 1437 |
7/8✓ Branch 0 taken 52196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 52189 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 52192 times.
|
52203 | if (dict_sys_t::is_dd_table_id(m_prebuilt->table->id) && |
| 1438 | 7 | innobase_need_rebuild(ha_alter_info, table, | |
| 1439 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | dict_table_is_file_per_table(m_prebuilt->table))) { |
| 1440 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | ut_ad(!m_prebuilt->table->is_temporary()); |
| 1441 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_NOT_ALLOWED_COMMAND, MYF(0)); |
| 1442 | 4 | return true; | |
| 1443 | } | ||
| 1444 | |||
| 1445 |
2/2✓ Branch 0 taken 4241 times.
✓ Branch 1 taken 47951 times.
|
52192 | if (altered_table->found_next_number_field != nullptr) { |
| 1446 |
2/4✓ Branch 0 taken 4241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4241 times.
✗ Branch 3 not taken.
|
4241 | dd_copy_autoinc(old_dd_tab->se_private_data(), |
| 1447 |
1/2✓ Branch 0 taken 4241 times.
✗ Branch 1 not taken.
|
4241 | new_dd_tab->se_private_data()); |
| 1448 |
1/2✓ Branch 0 taken 4241 times.
✗ Branch 1 not taken.
|
4241 | dd_set_autoinc(new_dd_tab->se_private_data(), |
| 1449 |
1/2✓ Branch 0 taken 4241 times.
✗ Branch 1 not taken.
|
4241 | ha_alter_info->create_info->auto_increment_value); |
| 1450 | } | ||
| 1451 | |||
| 1452 |
1/2✓ Branch 0 taken 52143 times.
✗ Branch 1 not taken.
|
52192 | return prepare_inplace_alter_table_impl<dd::Table>( |
| 1453 | 52143 | altered_table, ha_alter_info, old_dd_tab, new_dd_tab); | |
| 1454 | 52147 | } | |
| 1455 | |||
| 1456 | ✗ | int ha_innobase::parallel_scan_init(void *&scan_ctx, size_t *num_threads, | |
| 1457 | bool use_reserved_threads) { | ||
| 1458 | ✗ | if (dict_table_is_discarded(m_prebuilt->table)) { | |
| 1459 | ✗ | ib_senderrf(ha_thd(), IB_LOG_LEVEL_ERROR, ER_TABLESPACE_DISCARDED, | |
| 1460 | ✗ | m_prebuilt->table->name.m_name); | |
| 1461 | |||
| 1462 | ✗ | return (HA_ERR_NO_SUCH_TABLE); | |
| 1463 | } | ||
| 1464 | |||
| 1465 | ✗ | scan_ctx = nullptr; | |
| 1466 | |||
| 1467 | ✗ | update_thd(); | |
| 1468 | |||
| 1469 | ✗ | auto trx = m_prebuilt->trx; | |
| 1470 | |||
| 1471 | ✗ | innobase_register_trx(ht, ha_thd(), trx); | |
| 1472 | |||
| 1473 | ✗ | trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE); | |
| 1474 | |||
| 1475 | ✗ | trx_assign_read_view(trx); | |
| 1476 | |||
| 1477 | ✗ | size_t max_threads = thd_parallel_read_threads(m_prebuilt->trx->mysql_thd); | |
| 1478 | |||
| 1479 | ✗ | max_threads = | |
| 1480 | ✗ | Parallel_reader::available_threads(max_threads, use_reserved_threads); | |
| 1481 | |||
| 1482 | ✗ | if (max_threads == 0) { | |
| 1483 | ✗ | return (HA_ERR_GENERIC); | |
| 1484 | } | ||
| 1485 | |||
| 1486 | ✗ | const auto row_len = m_prebuilt->mysql_row_len; | |
| 1487 | |||
| 1488 | ✗ | auto adapter = ut::new_withkey<Parallel_reader_adapter>( | |
| 1489 | ✗ | UT_NEW_THIS_FILE_PSI_KEY, max_threads, row_len); | |
| 1490 | |||
| 1491 | ✗ | if (adapter == nullptr) { | |
| 1492 | ✗ | Parallel_reader::release_threads(max_threads); | |
| 1493 | ✗ | return (HA_ERR_OUT_OF_MEM); | |
| 1494 | } | ||
| 1495 | |||
| 1496 | ✗ | Parallel_reader::Scan_range full_scan{}; | |
| 1497 | |||
| 1498 | ✗ | Parallel_reader::Config config(full_scan, m_prebuilt->table->first_index()); | |
| 1499 | |||
| 1500 | dberr_t err = | ||
| 1501 | ✗ | adapter->add_scan(trx, config, [=](const Parallel_reader::Ctx *ctx) { | |
| 1502 | ✗ | return (adapter->process_rows(ctx)); | |
| 1503 | }); | ||
| 1504 | |||
| 1505 | ✗ | if (err != DB_SUCCESS) { | |
| 1506 | ✗ | ut::delete_(adapter); | |
| 1507 | ✗ | return (convert_error_code_to_mysql(err, 0, ha_thd())); | |
| 1508 | } | ||
| 1509 | |||
| 1510 | ✗ | scan_ctx = adapter; | |
| 1511 | ✗ | *num_threads = max_threads; | |
| 1512 | |||
| 1513 | ✗ | build_template(true); | |
| 1514 | |||
| 1515 | ✗ | adapter->set(m_prebuilt); | |
| 1516 | |||
| 1517 | ✗ | return (0); | |
| 1518 | } | ||
| 1519 | |||
| 1520 | ✗ | int ha_innobase::parallel_scan(void *scan_ctx, void **thread_ctxs, | |
| 1521 | Reader::Init_fn init_fn, Reader::Load_fn load_fn, | ||
| 1522 | Reader::End_fn end_fn) { | ||
| 1523 | ✗ | if (dict_table_is_discarded(m_prebuilt->table)) { | |
| 1524 | ✗ | ib_senderrf(ha_thd(), IB_LOG_LEVEL_ERROR, ER_TABLESPACE_DISCARDED, | |
| 1525 | ✗ | m_prebuilt->table->name.m_name); | |
| 1526 | |||
| 1527 | ✗ | return (HA_ERR_NO_SUCH_TABLE); | |
| 1528 | } | ||
| 1529 | |||
| 1530 | ✗ | ut_a(scan_ctx != nullptr); | |
| 1531 | |||
| 1532 | ✗ | update_thd(); | |
| 1533 | |||
| 1534 | ✗ | build_template(true); | |
| 1535 | |||
| 1536 | ✗ | auto adapter = static_cast<Parallel_reader_adapter *>(scan_ctx); | |
| 1537 | |||
| 1538 | ✗ | auto err = adapter->run(thread_ctxs, init_fn, load_fn, end_fn); | |
| 1539 | |||
| 1540 | ✗ | return (convert_error_code_to_mysql(err, 0, ha_thd())); | |
| 1541 | } | ||
| 1542 | |||
| 1543 | ✗ | void ha_innobase::parallel_scan_end(void *parallel_scan_ctx) { | |
| 1544 | ✗ | Parallel_reader_adapter *parallel_reader = | |
| 1545 | static_cast<Parallel_reader_adapter *>(parallel_scan_ctx); | ||
| 1546 | ✗ | ut::delete_(parallel_reader); | |
| 1547 | } | ||
| 1548 | |||
| 1549 | 51899 | bool ha_innobase::inplace_alter_table(TABLE *altered_table, | |
| 1550 | Alter_inplace_info *ha_alter_info, | ||
| 1551 | const dd::Table *old_dd_tab | ||
| 1552 | [[maybe_unused]], | ||
| 1553 | dd::Table *new_dd_tab [[maybe_unused]]) { | ||
| 1554 |
1/2✓ Branch 0 taken 51899 times.
✗ Branch 1 not taken.
|
51899 | DBUG_TRACE; |
| 1555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51899 times.
|
51899 | ut_ad(old_dd_tab != nullptr); |
| 1556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51899 times.
|
51899 | ut_ad(new_dd_tab != nullptr); |
| 1557 | |||
| 1558 | /* Notify clone during in place operations */ | ||
| 1559 | Clone_notify notifier(Clone_notify::Type::SPACE_ALTER_INPLACE, | ||
| 1560 |
1/2✓ Branch 0 taken 51899 times.
✗ Branch 1 not taken.
|
51899 | dict_sys_t::s_invalid_space_id, false); |
| 1561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51899 times.
|
51899 | ut_ad(!notifier.failed()); |
| 1562 | |||
| 1563 |
1/2✓ Branch 0 taken 51899 times.
✗ Branch 1 not taken.
|
103798 | return inplace_alter_table_impl<dd::Table>(altered_table, ha_alter_info); |
| 1564 | 51899 | } | |
| 1565 | |||
| 1566 | /** Commit or rollback the changes made during | ||
| 1567 | prepare_inplace_alter_table() and inplace_alter_table() inside | ||
| 1568 | the storage engine. Note that the allowed level of concurrency | ||
| 1569 | during this operation will be the same as for | ||
| 1570 | inplace_alter_table() and thus might be higher than during | ||
| 1571 | prepare_inplace_alter_table(). (E.g concurrent writes were | ||
| 1572 | blocked during prepare, but might not be during commit). | ||
| 1573 | @param[in] altered_table TABLE object for new version of table. | ||
| 1574 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 1575 | by ALTER TABLE and holding data used during in-place alter. | ||
| 1576 | @param[in] commit True to commit or false to rollback. | ||
| 1577 | @param[in] old_dd_tab dd::Table object representing old | ||
| 1578 | version of the table | ||
| 1579 | @param[in,out] new_dd_tab dd::Table object representing new | ||
| 1580 | version of the table. Can be adjusted by this call. Changes to the table | ||
| 1581 | definition will be persisted in the data-dictionary at statement | ||
| 1582 | commit time. | ||
| 1583 | @retval true Failure | ||
| 1584 | @retval false Success */ | ||
| 1585 | 52157 | bool ha_innobase::commit_inplace_alter_table(TABLE *altered_table, | |
| 1586 | Alter_inplace_info *ha_alter_info, | ||
| 1587 | bool commit, | ||
| 1588 | const dd::Table *old_dd_tab, | ||
| 1589 | dd::Table *new_dd_tab) { | ||
| 1590 |
1/2✓ Branch 0 taken 52157 times.
✗ Branch 1 not taken.
|
52157 | DBUG_TRACE; |
| 1591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52157 times.
|
52157 | ut_ad(old_dd_tab != nullptr); |
| 1592 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52157 times.
|
52157 | ut_ad(new_dd_tab != nullptr); |
| 1593 | |||
| 1594 | 52157 | ha_innobase_inplace_ctx *ctx = | |
| 1595 | static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | ||
| 1596 | |||
| 1597 | 52157 | alter_table_old_info_t old_info; | |
| 1598 | 52157 | ut_d(bool old_info_updated = false); | |
| 1599 |
4/4✓ Branch 0 taken 51776 times.
✓ Branch 1 taken 381 times.
✓ Branch 2 taken 44247 times.
✓ Branch 3 taken 7529 times.
|
52157 | if (commit && ctx != nullptr) { |
| 1600 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44247 times.
|
44247 | ut_ad(!!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)); |
| 1601 | 44247 | old_info.update(ctx->old_table, ctx->need_rebuild()); | |
| 1602 | 44247 | ut_d(old_info_updated = true); | |
| 1603 | } | ||
| 1604 | |||
| 1605 |
1/2✓ Branch 0 taken 52119 times.
✗ Branch 1 not taken.
|
52157 | bool res = commit_inplace_alter_table_impl<dd::Table>( |
| 1606 | altered_table, ha_alter_info, commit, new_dd_tab); | ||
| 1607 | |||
| 1608 |
4/4✓ Branch 0 taken 52108 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 381 times.
✓ Branch 3 taken 51727 times.
|
52119 | if (res || !commit) { |
| 1609 | 392 | return true; | |
| 1610 | } | ||
| 1611 | |||
| 1612 |
6/8✓ Branch 0 taken 44198 times.
✓ Branch 1 taken 7529 times.
✓ Branch 2 taken 27636 times.
✓ Branch 3 taken 16562 times.
✓ Branch 4 taken 27636 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 51727 times.
|
51727 | ut_ad(ctx == nullptr || !(ctx->need_rebuild() && is_instant(ha_alter_info))); |
| 1613 | |||
| 1614 |
2/2✓ Branch 0 taken 7529 times.
✓ Branch 1 taken 44198 times.
|
51727 | if (is_instant(ha_alter_info)) { |
| 1615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7529 times.
|
7529 | ut_ad(!res); |
| 1616 | |||
| 1617 | Instant_ddl_impl<dd::Table> executor( | ||
| 1618 | 7529 | ha_alter_info, m_user_thd, m_prebuilt->trx, m_prebuilt->table, table, | |
| 1619 | altered_table, old_dd_tab, new_dd_tab, | ||
| 1620 | 7529 | altered_table->found_next_number_field != nullptr | |
| 1621 | 272 | ? &m_prebuilt->table->autoinc | |
| 1622 |
2/2✓ Branch 0 taken 272 times.
✓ Branch 1 taken 7257 times.
|
7529 | : nullptr); |
| 1623 | |||
| 1624 | /* Execute Instant DDL */ | ||
| 1625 |
1/2✓ Branch 0 taken 7529 times.
✗ Branch 1 not taken.
|
7529 | executor.commit_instant_ddl(); |
| 1626 |
2/4✓ Branch 0 taken 44198 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 44198 times.
|
51727 | } else if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) || |
| 1627 | ctx == nullptr) { | ||
| 1628 | ✗ | ut_ad(!res); | |
| 1629 | ✗ | dd_commit_inplace_no_change(ha_alter_info, old_dd_tab, new_dd_tab, false); | |
| 1630 | } else { | ||
| 1631 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44198 times.
|
44198 | ut_ad(old_info_updated); |
| 1632 |
7/8✓ Branch 0 taken 16562 times.
✓ Branch 1 taken 27636 times.
✓ Branch 2 taken 16562 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16180 times.
✓ Branch 5 taken 382 times.
✓ Branch 6 taken 16180 times.
✓ Branch 7 taken 28018 times.
|
44198 | if (!ctx->need_rebuild() && !dict_table_has_fts_index(m_prebuilt->table)) { |
| 1633 | /* Table is not rebuilt so copy instant metadata. */ | ||
| 1634 |
1/2✓ Branch 0 taken 16180 times.
✗ Branch 1 not taken.
|
16180 | dd_inplace_alter_copy_instant_metadata(ha_alter_info, old_dd_tab, |
| 1635 | new_dd_tab); | ||
| 1636 | } | ||
| 1637 | |||
| 1638 |
1/2✓ Branch 0 taken 44198 times.
✗ Branch 1 not taken.
|
44198 | dd_commit_inplace_alter_table<dd::Table>(old_info, ctx->new_table, |
| 1639 | old_dd_tab, new_dd_tab); | ||
| 1640 |
2/2✓ Branch 0 taken 16562 times.
✓ Branch 1 taken 27636 times.
|
44198 | if (!ctx->need_rebuild()) { |
| 1641 |
1/2✓ Branch 0 taken 16562 times.
✗ Branch 1 not taken.
|
16562 | dd_commit_inplace_update_instant_meta(ctx->new_table, old_dd_tab, |
| 1642 | new_dd_tab); | ||
| 1643 | } | ||
| 1644 |
2/4✓ Branch 0 taken 44198 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 44198 times.
|
44198 | ut_ad(dd_table_match(ctx->new_table, new_dd_tab)); |
| 1645 | } | ||
| 1646 | |||
| 1647 | #ifdef UNIV_DEBUG | ||
| 1648 | /* Inplace ALTERs for expanded fast index creation can only be about | ||
| 1649 | DROP and ADD INDEX and never be instant operation */ | ||
| 1650 |
7/8✓ Branch 0 taken 51727 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 451 times.
✓ Branch 3 taken 51276 times.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 382 times.
✓ Branch 6 taken 388 times.
✓ Branch 7 taken 51339 times.
|
51796 | if (dd_table_has_instant_cols(*old_dd_tab) && |
| 1651 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 63 times.
|
69 | (ctx == nullptr || !ctx->need_rebuild())) { |
| 1652 |
3/10✓ Branch 0 taken 388 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 388 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 388 times.
|
388 | ut_ad(dd_table_has_instant_cols(*new_dd_tab) || |
| 1653 | (ctx == nullptr || ctx->new_table->skip_alter_undo)); | ||
| 1654 | } | ||
| 1655 | #endif /* UNIV_DEBUG */ | ||
| 1656 | |||
| 1657 | 51727 | return res; | |
| 1658 | 52119 | } | |
| 1659 | |||
| 1660 | /** Initialize the dict_foreign_t structure with supplied info | ||
| 1661 | @return true if added, false if duplicate foreign->id */ | ||
| 1662 | 98 | static bool innobase_init_foreign( | |
| 1663 | dict_foreign_t *foreign, /*!< in/out: structure to | ||
| 1664 | initialize */ | ||
| 1665 | const char *constraint_name, /*!< in/out: constraint name if | ||
| 1666 | exists */ | ||
| 1667 | dict_table_t *table, /*!< in: foreign table */ | ||
| 1668 | dict_index_t *index, /*!< in: foreign key index */ | ||
| 1669 | const char **column_names, /*!< in: foreign key column | ||
| 1670 | names */ | ||
| 1671 | ulint num_field, /*!< in: number of columns */ | ||
| 1672 | const char *referenced_table_name, /*!< in: referenced table | ||
| 1673 | name */ | ||
| 1674 | dict_table_t *referenced_table, /*!< in: referenced table */ | ||
| 1675 | dict_index_t *referenced_index, /*!< in: referenced index */ | ||
| 1676 | const char **referenced_column_names, /*!< in: referenced column | ||
| 1677 | names */ | ||
| 1678 | ulint referenced_num_field) /*!< in: number of referenced | ||
| 1679 | columns */ | ||
| 1680 | { | ||
| 1681 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
|
98 | ut_ad(dict_sys_mutex_own()); |
| 1682 | |||
| 1683 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | if (constraint_name) { |
| 1684 | ulint db_len; | ||
| 1685 | |||
| 1686 | /* Catenate 'databasename/' to the constraint name specified | ||
| 1687 | by the user: we conceive the constraint as belonging to the | ||
| 1688 | same MySQL 'database' as the table itself. We store the name | ||
| 1689 | to foreign->id. */ | ||
| 1690 | |||
| 1691 | 98 | db_len = dict_get_db_name_len(table->name.m_name); | |
| 1692 | |||
| 1693 | 196 | foreign->id = static_cast<char *>( | |
| 1694 | 98 | mem_heap_alloc(foreign->heap, db_len + strlen(constraint_name) + 2)); | |
| 1695 | |||
| 1696 | 98 | ut_memcpy(foreign->id, table->name.m_name, db_len); | |
| 1697 | 98 | foreign->id[db_len] = '/'; | |
| 1698 | 98 | strcpy(foreign->id + db_len + 1, constraint_name); | |
| 1699 | |||
| 1700 | /* Check if any existing foreign key has the same id, | ||
| 1701 | this is needed only if user supplies the constraint name */ | ||
| 1702 | |||
| 1703 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
|
98 | if (table->foreign_set.find(foreign) != table->foreign_set.end()) { |
| 1704 | ✗ | return (false); | |
| 1705 | } | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | 98 | foreign->foreign_table = table; | |
| 1709 | 196 | foreign->foreign_table_name = | |
| 1710 | 98 | mem_heap_strdup(foreign->heap, table->name.m_name); | |
| 1711 | 98 | dict_mem_foreign_table_name_lookup_set(foreign, true); | |
| 1712 | |||
| 1713 | 98 | foreign->foreign_index = index; | |
| 1714 | 98 | foreign->n_fields = (unsigned int)num_field; | |
| 1715 | |||
| 1716 | 196 | foreign->foreign_col_names = static_cast<const char **>( | |
| 1717 | 98 | mem_heap_alloc(foreign->heap, num_field * sizeof(void *))); | |
| 1718 | |||
| 1719 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 98 times.
|
214 | for (ulint i = 0; i < foreign->n_fields; i++) { |
| 1720 | 232 | foreign->foreign_col_names[i] = | |
| 1721 | 116 | mem_heap_strdup(foreign->heap, column_names[i]); | |
| 1722 | } | ||
| 1723 | |||
| 1724 | 98 | foreign->referenced_index = referenced_index; | |
| 1725 | 98 | foreign->referenced_table = referenced_table; | |
| 1726 | |||
| 1727 | 196 | foreign->referenced_table_name = | |
| 1728 | 98 | mem_heap_strdup(foreign->heap, referenced_table_name); | |
| 1729 | 98 | dict_mem_referenced_table_name_lookup_set(foreign, true); | |
| 1730 | |||
| 1731 | 196 | foreign->referenced_col_names = static_cast<const char **>( | |
| 1732 | 98 | mem_heap_alloc(foreign->heap, referenced_num_field * sizeof(void *))); | |
| 1733 | |||
| 1734 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 98 times.
|
214 | for (ulint i = 0; i < foreign->n_fields; i++) { |
| 1735 | 232 | foreign->referenced_col_names[i] = | |
| 1736 | 116 | mem_heap_strdup(foreign->heap, referenced_column_names[i]); | |
| 1737 | } | ||
| 1738 | |||
| 1739 | 98 | return (true); | |
| 1740 | } | ||
| 1741 | |||
| 1742 | /** Check whether the foreign key options is legit | ||
| 1743 | @return true if it is */ | ||
| 1744 | 98 | [[nodiscard]] static bool innobase_check_fk_option( | |
| 1745 | const dict_foreign_t *foreign) /*!< in: foreign key */ | ||
| 1746 | { | ||
| 1747 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 72 times.
|
98 | if (!foreign->foreign_index) { |
| 1748 | 26 | return (true); | |
| 1749 | } | ||
| 1750 | |||
| 1751 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 64 times.
|
72 | if (foreign->type & |
| 1752 | (DICT_FOREIGN_ON_UPDATE_SET_NULL | DICT_FOREIGN_ON_DELETE_SET_NULL)) { | ||
| 1753 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | for (ulint j = 0; j < foreign->n_fields; j++) { |
| 1754 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if ((foreign->foreign_index->get_col(j)->prtype) & DATA_NOT_NULL) { |
| 1755 | /* It is not sensible to define | ||
| 1756 | SET NULL if the column is not | ||
| 1757 | allowed to be NULL! */ | ||
| 1758 | ✗ | return (false); | |
| 1759 | } | ||
| 1760 | } | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | 72 | return (true); | |
| 1764 | } | ||
| 1765 | |||
| 1766 | /** Set foreign key options | ||
| 1767 | @return true if successfully set */ | ||
| 1768 | 98 | [[nodiscard]] static bool innobase_set_foreign_key_option( | |
| 1769 | dict_foreign_t *foreign, /*!< in:InnoDB Foreign key */ | ||
| 1770 | const Foreign_key_spec *fk_key) /*!< in: Foreign key info from | ||
| 1771 | MySQL */ | ||
| 1772 | { | ||
| 1773 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
|
98 | ut_ad(!foreign->type); |
| 1774 | |||
| 1775 |
4/5✓ Branch 0 taken 13 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 59 times.
✗ Branch 4 not taken.
|
98 | switch (fk_key->delete_opt) { |
| 1776 | 13 | case FK_OPTION_NO_ACTION: | |
| 1777 | case FK_OPTION_RESTRICT: | ||
| 1778 | case FK_OPTION_DEFAULT: | ||
| 1779 | 13 | foreign->type = DICT_FOREIGN_ON_DELETE_NO_ACTION; | |
| 1780 | 13 | break; | |
| 1781 | 16 | case FK_OPTION_CASCADE: | |
| 1782 | 16 | foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE; | |
| 1783 | 16 | break; | |
| 1784 | 10 | case FK_OPTION_SET_NULL: | |
| 1785 | 10 | foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL; | |
| 1786 | 10 | break; | |
| 1787 | 59 | case FK_OPTION_UNDEF: | |
| 1788 | 59 | break; | |
| 1789 | } | ||
| 1790 | |||
| 1791 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
|
98 | switch (fk_key->update_opt) { |
| 1792 | ✗ | case FK_OPTION_NO_ACTION: | |
| 1793 | case FK_OPTION_RESTRICT: | ||
| 1794 | case FK_OPTION_DEFAULT: | ||
| 1795 | ✗ | foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION; | |
| 1796 | ✗ | break; | |
| 1797 | 48 | case FK_OPTION_CASCADE: | |
| 1798 | 48 | foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE; | |
| 1799 | 48 | break; | |
| 1800 | 4 | case FK_OPTION_SET_NULL: | |
| 1801 | 4 | foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL; | |
| 1802 | 4 | break; | |
| 1803 | 46 | case FK_OPTION_UNDEF: | |
| 1804 | 46 | break; | |
| 1805 | } | ||
| 1806 | |||
| 1807 | 98 | return (innobase_check_fk_option(foreign)); | |
| 1808 | } | ||
| 1809 | |||
| 1810 | /** Check if a foreign key constraint can make use of an index | ||
| 1811 | that is being created. | ||
| 1812 | @return useable index, or NULL if none found */ | ||
| 1813 | 38 | [[nodiscard]] static const KEY *innobase_find_equiv_index( | |
| 1814 | const char *const *col_names, | ||
| 1815 | /*!< in: column names */ | ||
| 1816 | uint n_cols, /*!< in: number of columns */ | ||
| 1817 | const KEY *keys, /*!< in: index information */ | ||
| 1818 | const uint *add, /*!< in: indexes being created */ | ||
| 1819 | uint n_add) /*!< in: number of indexes to create */ | ||
| 1820 | { | ||
| 1821 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1 times.
|
41 | for (uint i = 0; i < n_add; i++) { |
| 1822 | 40 | const KEY *key = &keys[add[i]]; | |
| 1823 | |||
| 1824 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
|
40 | if (key->user_defined_key_parts < n_cols || key->flags & HA_SPATIAL) { |
| 1825 | ✗ | no_match: | |
| 1826 | 3 | continue; | |
| 1827 | } | ||
| 1828 | |||
| 1829 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 37 times.
|
83 | for (uint j = 0; j < n_cols; j++) { |
| 1830 | 46 | const KEY_PART_INFO &key_part = key->key_part[j]; | |
| 1831 | 46 | uint32_t col_len = key_part.field->pack_length(); | |
| 1832 | |||
| 1833 | /* Any index on virtual columns cannot be used | ||
| 1834 | for reference constaint */ | ||
| 1835 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
46 | if (innobase_is_v_fld(key_part.field)) { |
| 1836 | ✗ | goto no_match; | |
| 1837 | } | ||
| 1838 | |||
| 1839 | /* The MySQL pack length contains 1 or 2 bytes | ||
| 1840 | length field for a true VARCHAR. */ | ||
| 1841 | |||
| 1842 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (key_part.field->type() == MYSQL_TYPE_VARCHAR) { |
| 1843 | ✗ | col_len -= key_part.field->get_length_bytes(); | |
| 1844 | } | ||
| 1845 | |||
| 1846 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (key_part.length < col_len) { |
| 1847 | /* Column prefix indexes cannot be | ||
| 1848 | used for FOREIGN KEY constraints. */ | ||
| 1849 | ✗ | goto no_match; | |
| 1850 | } | ||
| 1851 | |||
| 1852 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 43 times.
|
46 | if (innobase_strcasecmp(col_names[j], key_part.field->field_name)) { |
| 1853 | /* Name mismatch */ | ||
| 1854 | 3 | goto no_match; | |
| 1855 | } | ||
| 1856 | } | ||
| 1857 | |||
| 1858 | 37 | return (key); | |
| 1859 | } | ||
| 1860 | |||
| 1861 | 1 | return (nullptr); | |
| 1862 | } | ||
| 1863 | |||
| 1864 | /** Find an index whose first fields are the columns in the array | ||
| 1865 | in the same order and is not marked for deletion | ||
| 1866 | @return matching index, NULL if not found */ | ||
| 1867 | 100 | [[nodiscard]] static dict_index_t *innobase_find_fk_index( | |
| 1868 | dict_table_t *table, /*!< in: table */ | ||
| 1869 | const char **col_names, | ||
| 1870 | /*!< in: column names, or NULL | ||
| 1871 | to use table->col_names */ | ||
| 1872 | dict_index_t **drop_index, | ||
| 1873 | /*!< in: indexes to be dropped */ | ||
| 1874 | ulint n_drop_index, | ||
| 1875 | /*!< in: size of drop_index[] */ | ||
| 1876 | const char **columns, /*!< in: array of column names */ | ||
| 1877 | ulint n_cols) /*!< in: number of columns */ | ||
| 1878 | { | ||
| 1879 | dict_index_t *index; | ||
| 1880 | |||
| 1881 | 100 | index = table->first_index(); | |
| 1882 | |||
| 1883 |
2/2✓ Branch 0 taken 207 times.
✓ Branch 1 taken 26 times.
|
233 | while (index != nullptr) { |
| 1884 |
4/4✓ Branch 0 taken 206 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 130 times.
|
413 | if (!(index->type & DICT_FTS) && |
| 1885 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 129 times.
|
206 | dict_foreign_qualify_index(table, col_names, columns, n_cols, index, |
| 1886 | nullptr, true, 0)) { | ||
| 1887 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 74 times.
|
78 | for (ulint i = 0; i < n_drop_index; i++) { |
| 1888 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (index == drop_index[i]) { |
| 1889 | /* Skip to-be-dropped indexes. */ | ||
| 1890 | 3 | goto next_rec; | |
| 1891 | } | ||
| 1892 | } | ||
| 1893 | |||
| 1894 | 74 | return (index); | |
| 1895 | } | ||
| 1896 | |||
| 1897 | 130 | next_rec: | |
| 1898 | 133 | index = index->next(); | |
| 1899 | } | ||
| 1900 | |||
| 1901 | 26 | return (nullptr); | |
| 1902 | } | ||
| 1903 | |||
| 1904 | /** Check whether given column is a base of stored column. | ||
| 1905 | @param[in] col_name column name | ||
| 1906 | @param[in] table table | ||
| 1907 | @param[in] s_cols list of stored columns | ||
| 1908 | @return true if the given column is a base of stored column,else false. */ | ||
| 1909 | 4 | static bool innobase_col_check_fk(const char *col_name, | |
| 1910 | const dict_table_t *table, | ||
| 1911 | dict_s_col_list *s_cols) { | ||
| 1912 | 4 | dict_s_col_list::const_iterator it; | |
| 1913 | |||
| 1914 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | for (it = s_cols->begin(); it != s_cols->end(); ++it) { |
| 1915 | 4 | dict_s_col_t s_col = *it; | |
| 1916 | |||
| 1917 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | for (ulint j = 0; j < s_col.num_base; j++) { |
| 1918 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (strcmp(col_name, table->get_col_name(s_col.base_col[j]->ind)) == 0) { |
| 1919 | 1 | return (true); | |
| 1920 | } | ||
| 1921 | } | ||
| 1922 | } | ||
| 1923 | |||
| 1924 | 3 | return (false); | |
| 1925 | } | ||
| 1926 | |||
| 1927 | /** Check whether the foreign key constraint is on base of any stored columns. | ||
| 1928 | @param[in] foreign Foriegn key constraing information | ||
| 1929 | @param[in] table table to which the foreign key objects | ||
| 1930 | to be added | ||
| 1931 | @param[in] s_cols list of stored column information in the table. | ||
| 1932 | @return true if yes, otherwise false. */ | ||
| 1933 | 97 | static bool innobase_check_fk_stored(const dict_foreign_t *foreign, | |
| 1934 | const dict_table_t *table, | ||
| 1935 | dict_s_col_list *s_cols) { | ||
| 1936 | 97 | ulint type = foreign->type; | |
| 1937 | |||
| 1938 | 97 | type &= | |
| 1939 | ~(DICT_FOREIGN_ON_DELETE_NO_ACTION | DICT_FOREIGN_ON_UPDATE_NO_ACTION); | ||
| 1940 | |||
| 1941 |
4/4✓ Branch 0 taken 60 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 4 times.
|
97 | if (type == 0 || s_cols == nullptr) { |
| 1942 | 93 | return (false); | |
| 1943 | } | ||
| 1944 | |||
| 1945 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | for (ulint i = 0; i < foreign->n_fields; i++) { |
| 1946 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (innobase_col_check_fk(foreign->foreign_col_names[i], table, s_cols)) { |
| 1947 | 1 | return (true); | |
| 1948 | } | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | 3 | return (false); | |
| 1952 | } | ||
| 1953 | |||
| 1954 | /** Create InnoDB foreign key structure from MySQL alter_info | ||
| 1955 | @param[in] ha_alter_info alter table info | ||
| 1956 | @param[in] table_share TABLE_SHARE | ||
| 1957 | @param[in] table table object | ||
| 1958 | @param[in] col_names column names, or NULL to use | ||
| 1959 | table->col_names | ||
| 1960 | @param[in] drop_index indexes to be dropped | ||
| 1961 | @param[in] n_drop_index size of drop_index | ||
| 1962 | @param[out] add_fk foreign constraint added | ||
| 1963 | @param[out] n_add_fk number of foreign constraints | ||
| 1964 | added | ||
| 1965 | @param[in] trx user transaction | ||
| 1966 | @param[in] s_cols list of stored column information | ||
| 1967 | @retval true if successful | ||
| 1968 | @retval false on error (will call my_error()) */ | ||
| 1969 | 94 | [[nodiscard]] static bool innobase_get_foreign_key_info( | |
| 1970 | Alter_inplace_info *ha_alter_info, const TABLE_SHARE *table_share, | ||
| 1971 | dict_table_t *table, const char **col_names, dict_index_t **drop_index, | ||
| 1972 | ulint n_drop_index, dict_foreign_t **add_fk, ulint *n_add_fk, | ||
| 1973 | const trx_t *trx, dict_s_col_list *s_cols) { | ||
| 1974 | const Foreign_key_spec *fk_key; | ||
| 1975 | 94 | dict_table_t *referenced_table = nullptr; | |
| 1976 | 94 | char *referenced_table_name = nullptr; | |
| 1977 | 94 | ulint num_fk = 0; | |
| 1978 | 94 | Alter_info *alter_info = ha_alter_info->alter_info; | |
| 1979 | MDL_ticket *mdl; | ||
| 1980 | |||
| 1981 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
94 | DBUG_TRACE; |
| 1982 | |||
| 1983 | 94 | *n_add_fk = 0; | |
| 1984 | |||
| 1985 |
3/4✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 381 times.
✓ Branch 3 taken 90 times.
|
471 | for (const Key_spec *key : alter_info->key_list) { |
| 1986 |
2/2✓ Branch 0 taken 281 times.
✓ Branch 1 taken 100 times.
|
381 | if (key->type != KEYTYPE_FOREIGN) { |
| 1987 | 281 | continue; | |
| 1988 | } | ||
| 1989 | |||
| 1990 | const char *column_names[MAX_NUM_FK_COLUMNS]; | ||
| 1991 | 100 | dict_index_t *index = nullptr; | |
| 1992 | const char *referenced_column_names[MAX_NUM_FK_COLUMNS]; | ||
| 1993 | 100 | dict_index_t *referenced_index = nullptr; | |
| 1994 | 100 | ulint num_col = 0; | |
| 1995 | 100 | ulint referenced_num_col = 0; | |
| 1996 | bool correct_option; | ||
| 1997 | 100 | char *db_namep = nullptr; | |
| 1998 | 100 | char *tbl_namep = nullptr; | |
| 1999 | 100 | ulint db_name_len = 0; | |
| 2000 | 100 | ulint tbl_name_len = 0; | |
| 2001 | char db_name[MAX_DATABASE_NAME_LEN]; | ||
| 2002 | char tbl_name[MAX_TABLE_NAME_LEN]; | ||
| 2003 | |||
| 2004 | 100 | fk_key = down_cast<const Foreign_key_spec *>(key); | |
| 2005 | |||
| 2006 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | if (fk_key->columns.size() > 0) { |
| 2007 | 100 | size_t i = 0; | |
| 2008 | |||
| 2009 | /* Get all the foreign key column info for the | ||
| 2010 | current table */ | ||
| 2011 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 100 times.
|
220 | while (i < fk_key->columns.size()) { |
| 2012 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | column_names[i] = fk_key->columns[i]->get_field_name(); |
| 2013 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | ut_ad(i < MAX_NUM_FK_COLUMNS); |
| 2014 | 120 | i++; | |
| 2015 | } | ||
| 2016 | |||
| 2017 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | index = innobase_find_fk_index(table, col_names, drop_index, n_drop_index, |
| 2018 | column_names, i); | ||
| 2019 | |||
| 2020 | /* MySQL would add a index in the creation | ||
| 2021 | list if no such index for foreign table, | ||
| 2022 | so we have to use DBUG_EXECUTE_IF to simulate | ||
| 2023 | the scenario */ | ||
| 2024 |
3/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 99 times.
|
100 | DBUG_EXECUTE_IF("innodb_test_no_foreign_idx", index = nullptr;); |
| 2025 | |||
| 2026 | /* Check whether there exist such | ||
| 2027 | index in the the index create clause */ | ||
| 2028 |
4/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 99 times.
|
127 | if (!index && |
| 2029 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
|
27 | !innobase_find_equiv_index(column_names, static_cast<uint>(i), |
| 2030 | 27 | ha_alter_info->key_info_buffer, | |
| 2031 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | ha_alter_info->index_add_buffer, |
| 2032 | ha_alter_info->index_add_count)) { | ||
| 2033 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_NO_INDEX_CHILD, MYF(0), |
| 2034 | 1 | fk_key->name.str ? fk_key->name.str : "", | |
| 2035 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | table_share->table_name.str); |
| 2036 | 4 | goto err_exit; | |
| 2037 | } | ||
| 2038 | |||
| 2039 | 99 | num_col = i; | |
| 2040 | } | ||
| 2041 | |||
| 2042 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | add_fk[num_fk] = dict_mem_foreign_create(); |
| 2043 | |||
| 2044 | #ifndef _WIN32 | ||
| 2045 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | if (fk_key->ref_db.str) { |
| 2046 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | tablename_to_filename(fk_key->ref_db.str, db_name, MAX_DATABASE_NAME_LEN); |
| 2047 | 99 | db_namep = db_name; | |
| 2048 | 99 | db_name_len = strlen(db_name); | |
| 2049 | } | ||
| 2050 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | if (fk_key->ref_table.str) { |
| 2051 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | tablename_to_filename(fk_key->ref_table.str, tbl_name, |
| 2052 | MAX_TABLE_NAME_LEN); | ||
| 2053 | 99 | tbl_namep = tbl_name; | |
| 2054 | 99 | tbl_name_len = strlen(tbl_name); | |
| 2055 | } | ||
| 2056 | #else | ||
| 2057 | ut_ad(fk_key->ref_table.str); | ||
| 2058 | tablename_to_filename(fk_key->ref_table.str, tbl_name, MAX_TABLE_NAME_LEN); | ||
| 2059 | innobase_casedn_str(tbl_name); | ||
| 2060 | tbl_name_len = strlen(tbl_name); | ||
| 2061 | tbl_namep = &tbl_name[0]; | ||
| 2062 | |||
| 2063 | if (fk_key->ref_db.str != NULL) { | ||
| 2064 | tablename_to_filename(fk_key->ref_db.str, db_name, MAX_DATABASE_NAME_LEN); | ||
| 2065 | innobase_casedn_str(db_name); | ||
| 2066 | db_name_len = strlen(db_name); | ||
| 2067 | db_namep = &db_name[0]; | ||
| 2068 | } | ||
| 2069 | #endif | ||
| 2070 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | dict_sys_mutex_enter(); |
| 2071 | |||
| 2072 | 198 | referenced_table_name = dd_get_referenced_table( | |
| 2073 | 99 | table->name.m_name, db_namep, db_name_len, tbl_namep, tbl_name_len, | |
| 2074 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | &referenced_table, &mdl, add_fk[num_fk]->heap); |
| 2075 | |||
| 2076 | /* Test the case when referenced_table failed to | ||
| 2077 | open, if trx->check_foreigns is not set, we should | ||
| 2078 | still be able to add the foreign key */ | ||
| 2079 |
6/10✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
99 | DBUG_EXECUTE_IF( |
| 2080 | "innodb_test_open_ref_fail", if (referenced_table) { | ||
| 2081 | dd_table_close(referenced_table, current_thd, &mdl, true); | ||
| 2082 | referenced_table = nullptr; | ||
| 2083 | }); | ||
| 2084 | |||
| 2085 |
3/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
99 | if (!referenced_table && trx->check_foreigns) { |
| 2086 | ✗ | dict_sys_mutex_exit(); | |
| 2087 | ✗ | my_error(ER_FK_CANNOT_OPEN_PARENT, MYF(0), tbl_namep); | |
| 2088 | |||
| 2089 | ✗ | goto err_exit; | |
| 2090 | } | ||
| 2091 | |||
| 2092 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | if (fk_key->ref_columns.size() > 0) { |
| 2093 | 99 | size_t i = 0; | |
| 2094 | |||
| 2095 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 99 times.
|
217 | while (i < fk_key->ref_columns.size()) { |
| 2096 |
1/2✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
|
118 | referenced_column_names[i] = fk_key->ref_columns[i]->get_field_name(); |
| 2097 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
|
118 | ut_ad(i < MAX_NUM_FK_COLUMNS); |
| 2098 | 118 | i++; | |
| 2099 | } | ||
| 2100 | |||
| 2101 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 27 times.
|
99 | if (referenced_table) { |
| 2102 |
1/2✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
|
72 | referenced_index = dict_foreign_find_index(referenced_table, nullptr, |
| 2103 | referenced_column_names, i, | ||
| 2104 | index, true, false); | ||
| 2105 | |||
| 2106 |
3/4✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 71 times.
|
72 | DBUG_EXECUTE_IF("innodb_test_no_reference_idx", |
| 2107 | referenced_index = nullptr;); | ||
| 2108 | |||
| 2109 | /* Check whether there exist such | ||
| 2110 | index in the the index create clause */ | ||
| 2111 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 71 times.
|
72 | if (!referenced_index) { |
| 2112 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | dd_table_close(referenced_table, current_thd, &mdl, true); |
| 2113 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | dict_sys_mutex_exit(); |
| 2114 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_NO_INDEX_PARENT, MYF(0), |
| 2115 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fk_key->name.str ? fk_key->name.str : "", tbl_namep); |
| 2116 | 1 | goto err_exit; | |
| 2117 | } | ||
| 2118 | } else { | ||
| 2119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | ut_a(!trx->check_foreigns); |
| 2120 | } | ||
| 2121 | |||
| 2122 | 98 | referenced_num_col = i; | |
| 2123 | } else { | ||
| 2124 | /* Not possible to add a foreign key without a | ||
| 2125 | referenced column */ | ||
| 2126 | ✗ | if (referenced_table) { | |
| 2127 | ✗ | dd_table_close(referenced_table, current_thd, &mdl, true); | |
| 2128 | } | ||
| 2129 | ✗ | dict_sys_mutex_exit(); | |
| 2130 | ✗ | my_error(ER_CANNOT_ADD_FOREIGN, MYF(0), tbl_namep); | |
| 2131 | ✗ | goto err_exit; | |
| 2132 | } | ||
| 2133 | |||
| 2134 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
|
98 | if (!innobase_init_foreign(add_fk[num_fk], fk_key->name.str, table, index, |
| 2135 | column_names, num_col, referenced_table_name, | ||
| 2136 | referenced_table, referenced_index, | ||
| 2137 | referenced_column_names, referenced_num_col)) { | ||
| 2138 | ✗ | if (referenced_table) { | |
| 2139 | ✗ | dd_table_close(referenced_table, current_thd, &mdl, true); | |
| 2140 | } | ||
| 2141 | ✗ | dict_sys_mutex_exit(); | |
| 2142 | ✗ | my_error(ER_FK_DUP_NAME, MYF(0), add_fk[num_fk]->id); | |
| 2143 | ✗ | goto err_exit; | |
| 2144 | } | ||
| 2145 | |||
| 2146 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 27 times.
|
98 | if (referenced_table) { |
| 2147 |
2/4✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
|
71 | dd_table_close(referenced_table, current_thd, &mdl, true); |
| 2148 | } | ||
| 2149 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | dict_sys_mutex_exit(); |
| 2150 | |||
| 2151 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | correct_option = innobase_set_foreign_key_option(add_fk[num_fk], fk_key); |
| 2152 | |||
| 2153 |
3/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 97 times.
|
98 | DBUG_EXECUTE_IF("innodb_test_wrong_fk_option", correct_option = false;); |
| 2154 | |||
| 2155 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97 times.
|
98 | if (!correct_option) { |
| 2156 | 1 | my_error(ER_FK_INCORRECT_OPTION, MYF(0), table_share->table_name.str, | |
| 2157 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | add_fk[num_fk]->id); |
| 2158 | 1 | goto err_exit; | |
| 2159 | } | ||
| 2160 | |||
| 2161 |
3/4✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 96 times.
|
97 | if (innobase_check_fk_stored(add_fk[num_fk], table, s_cols)) { |
| 2162 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED, MYF(0)); |
| 2163 | 1 | goto err_exit; | |
| 2164 | } | ||
| 2165 | |||
| 2166 | 96 | num_fk++; | |
| 2167 | } | ||
| 2168 | |||
| 2169 | 90 | *n_add_fk = num_fk; | |
| 2170 | |||
| 2171 | 90 | return true; | |
| 2172 | 4 | err_exit: | |
| 2173 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | for (ulint i = 0; i <= num_fk; i++) { |
| 2174 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (add_fk[i]) { |
| 2175 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | dict_foreign_free(add_fk[i]); |
| 2176 | } | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | 4 | return false; | |
| 2180 | 94 | } | |
| 2181 | |||
| 2182 | /** Copies an InnoDB column to a MySQL field. This function is | ||
| 2183 | adapted from row_sel_field_store_in_mysql_format(). */ | ||
| 2184 | 98 | static void innobase_col_to_mysql( | |
| 2185 | const dict_col_t *col, /*!< in: InnoDB column */ | ||
| 2186 | const uchar *data, /*!< in: InnoDB column data */ | ||
| 2187 | ulint len, /*!< in: length of data, in bytes */ | ||
| 2188 | Field *field) /*!< in/out: MySQL field */ | ||
| 2189 | { | ||
| 2190 | uchar *ptr; | ||
| 2191 | 98 | uchar *dest = field->field_ptr(); | |
| 2192 | 98 | ulint flen = field->pack_length(); | |
| 2193 | |||
| 2194 |
5/7✓ Branch 0 taken 55 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
|
98 | switch (col->mtype) { |
| 2195 | 55 | case DATA_INT: | |
| 2196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | ut_ad(len == flen); |
| 2197 | |||
| 2198 | /* Convert integer data from Innobase to little-endian | ||
| 2199 | format, sign bit restored to normal */ | ||
| 2200 | |||
| 2201 |
2/2✓ Branch 0 taken 227 times.
✓ Branch 1 taken 55 times.
|
282 | for (ptr = dest + len; ptr != dest;) { |
| 2202 | 227 | *--ptr = *data++; | |
| 2203 | } | ||
| 2204 | |||
| 2205 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (!field->is_flag_set(UNSIGNED_FLAG)) { |
| 2206 | 55 | ((byte *)dest)[len - 1] ^= 0x80; | |
| 2207 | } | ||
| 2208 | |||
| 2209 | 55 | break; | |
| 2210 | |||
| 2211 | 8 | case DATA_VARCHAR: | |
| 2212 | case DATA_VARMYSQL: | ||
| 2213 | case DATA_BINARY: | ||
| 2214 | 8 | field->reset(); | |
| 2215 | |||
| 2216 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (field->type() == MYSQL_TYPE_VARCHAR) { |
| 2217 | /* This is a >= 5.0.3 type true VARCHAR. Store the | ||
| 2218 | length of the data to the first byte or the first | ||
| 2219 | two bytes of dest. */ | ||
| 2220 | |||
| 2221 | dest = | ||
| 2222 | 8 | row_mysql_store_true_var_len(dest, len, flen - field->key_length()); | |
| 2223 | } | ||
| 2224 | |||
| 2225 | /* Copy the actual data */ | ||
| 2226 | 8 | memcpy(dest, data, len); | |
| 2227 | 8 | break; | |
| 2228 | |||
| 2229 | 17 | case DATA_VAR_POINT: | |
| 2230 | case DATA_GEOMETRY: | ||
| 2231 | case DATA_BLOB: | ||
| 2232 | /* Skip MySQL BLOBs when reporting an erroneous row | ||
| 2233 | during index creation or table rebuild. */ | ||
| 2234 | 17 | field->set_null(); | |
| 2235 | 17 | break; | |
| 2236 | |||
| 2237 | #ifdef UNIV_DEBUG | ||
| 2238 | 4 | case DATA_MYSQL: | |
| 2239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_ad(flen >= len); |
| 2240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_ad(DATA_MBMAXLEN(col->mbminmaxlen) >= DATA_MBMINLEN(col->mbminmaxlen)); |
| 2241 | 4 | memcpy(dest, data, len); | |
| 2242 | 4 | break; | |
| 2243 | |||
| 2244 | ✗ | default: | |
| 2245 | case DATA_SYS_CHILD: | ||
| 2246 | case DATA_SYS: | ||
| 2247 | /* These column types should never be shipped to MySQL. */ | ||
| 2248 | ✗ | ut_d(ut_error); | |
| 2249 | [[fallthrough]]; | ||
| 2250 | |||
| 2251 | ✗ | case DATA_FLOAT: | |
| 2252 | case DATA_DOUBLE: | ||
| 2253 | case DATA_DECIMAL: | ||
| 2254 | case DATA_POINT: | ||
| 2255 | /* Above are the valid column types for MySQL data. */ | ||
| 2256 | ✗ | ut_ad(flen == len); | |
| 2257 | [[fallthrough]]; | ||
| 2258 | case DATA_FIXBINARY: | ||
| 2259 | case DATA_CHAR: | ||
| 2260 | /* We may have flen > len when there is a shorter | ||
| 2261 | prefix on the CHAR and BINARY column. */ | ||
| 2262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
14 | ut_ad(flen >= len); |
| 2263 | #else /* UNIV_DEBUG */ | ||
| 2264 | default: | ||
| 2265 | #endif /* UNIV_DEBUG */ | ||
| 2266 | 15 | memcpy(dest, data, len); | |
| 2267 | } | ||
| 2268 | 99 | } | |
| 2269 | |||
| 2270 | /** Copies an InnoDB record to table->record[0]. | ||
| 2271 | @param[in,out] table Mysql table | ||
| 2272 | @param[in] rec Record | ||
| 2273 | @param[in] index Index | ||
| 2274 | @param[in] offsets rec_get_offsets( rec, index, ...) */ | ||
| 2275 | ✗ | void innobase_rec_to_mysql(struct TABLE *table, const rec_t *rec, | |
| 2276 | const dict_index_t *index, const ulint *offsets) { | ||
| 2277 | ✗ | uint n_fields = table->s->fields; | |
| 2278 | |||
| 2279 | ✗ | ut_ad(n_fields == | |
| 2280 | dict_table_get_n_tot_u_cols(index->table) - | ||
| 2281 | DICT_TF2_FLAG_IS_SET(index->table, DICT_TF2_FTS_HAS_DOC_ID)); | ||
| 2282 | |||
| 2283 | ✗ | for (uint i = 0; i < n_fields; i++) { | |
| 2284 | ✗ | Field *field = table->field[i]; | |
| 2285 | ulint ipos; | ||
| 2286 | ulint ilen; | ||
| 2287 | const uchar *ifield; | ||
| 2288 | |||
| 2289 | ✗ | field->reset(); | |
| 2290 | |||
| 2291 | ✗ | ipos = index->get_col_pos(i, true, false, nullptr); | |
| 2292 | |||
| 2293 | ✗ | if (ipos == ULINT_UNDEFINED || rec_offs_nth_extern(index, offsets, ipos)) { | |
| 2294 | ✗ | null_field: | |
| 2295 | ✗ | field->set_null(); | |
| 2296 | ✗ | continue; | |
| 2297 | } | ||
| 2298 | |||
| 2299 | ✗ | ifield = rec_get_nth_field_instant(rec, offsets, ipos, index, &ilen); | |
| 2300 | |||
| 2301 | /* Assign the NULL flag */ | ||
| 2302 | ✗ | if (ilen == UNIV_SQL_NULL) { | |
| 2303 | ✗ | ut_ad(field->is_nullable()); | |
| 2304 | ✗ | goto null_field; | |
| 2305 | } | ||
| 2306 | |||
| 2307 | ✗ | field->set_notnull(); | |
| 2308 | |||
| 2309 | ✗ | innobase_col_to_mysql(index->get_field(ipos)->col, ifield, ilen, field); | |
| 2310 | } | ||
| 2311 | } | ||
| 2312 | |||
| 2313 | /** Copies an InnoDB index entry to table->record[0]. | ||
| 2314 | @param[in,out] table Mysql table | ||
| 2315 | @param[in] index Innodb index | ||
| 2316 | @param[in] fields Innodb index fields */ | ||
| 2317 | 39 | void innobase_fields_to_mysql(struct TABLE *table, const dict_index_t *index, | |
| 2318 | const dfield_t *fields) { | ||
| 2319 | 39 | uint n_fields = table->s->fields; | |
| 2320 | 39 | ulint num_v = 0; | |
| 2321 | |||
| 2322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | ut_ad(n_fields == |
| 2323 | index->table->get_n_user_cols() + | ||
| 2324 | dict_table_get_n_v_cols(index->table) - | ||
| 2325 | DICT_TF2_FLAG_IS_SET(index->table, DICT_TF2_FTS_HAS_DOC_ID)); | ||
| 2326 | |||
| 2327 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 39 times.
|
157 | for (uint i = 0; i < n_fields; i++) { |
| 2328 | 118 | Field *field = table->field[i]; | |
| 2329 | ulint ipos; | ||
| 2330 | ulint col_n; | ||
| 2331 | |||
| 2332 | 118 | field->reset(); | |
| 2333 | |||
| 2334 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
117 | if (innobase_is_v_fld(field)) { |
| 2335 | 1 | col_n = num_v; | |
| 2336 | 1 | num_v++; | |
| 2337 | } else { | ||
| 2338 | 116 | col_n = i - num_v; | |
| 2339 | } | ||
| 2340 | |||
| 2341 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
117 | ipos = index->get_col_pos(col_n, true, innobase_is_v_fld(field), nullptr); |
| 2342 | |||
| 2343 |
6/6✓ Branch 0 taken 96 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 90 times.
|
207 | if (ipos == ULINT_UNDEFINED || dfield_is_ext(&fields[ipos]) || |
| 2344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | dfield_is_null(&fields[ipos])) { |
| 2345 | 27 | field->set_null(); | |
| 2346 | } else { | ||
| 2347 | 90 | field->set_notnull(); | |
| 2348 | |||
| 2349 | 90 | const dfield_t *df = &fields[ipos]; | |
| 2350 | |||
| 2351 | 90 | innobase_col_to_mysql(index->get_field(ipos)->col, | |
| 2352 | 90 | static_cast<const uchar *>(dfield_get_data(df)), | |
| 2353 | 90 | dfield_get_len(df), field); | |
| 2354 | } | ||
| 2355 | } | ||
| 2356 | 39 | } | |
| 2357 | |||
| 2358 | /** Copies an InnoDB row to table->record[0]. | ||
| 2359 | @param[in,out] table Mysql table | ||
| 2360 | @param[in] itab Innodb table | ||
| 2361 | @param[in] row Innodb row */ | ||
| 2362 | 5 | void innobase_row_to_mysql(struct TABLE *table, const dict_table_t *itab, | |
| 2363 | const dtuple_t *row) { | ||
| 2364 | 5 | uint n_fields = table->s->fields; | |
| 2365 | 5 | ulint num_v = 0; | |
| 2366 | |||
| 2367 | /* The InnoDB row may contain an extra FTS_DOC_ID column at the end. */ | ||
| 2368 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | ut_ad(row->n_fields == itab->get_n_cols()); |
| 2369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | ut_ad(n_fields == row->n_fields - DATA_N_SYS_COLS + |
| 2370 | dict_table_get_n_v_cols(itab) - | ||
| 2371 | DICT_TF2_FLAG_IS_SET(itab, DICT_TF2_FTS_HAS_DOC_ID)); | ||
| 2372 | |||
| 2373 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
|
18 | for (uint i = 0; i < n_fields; i++) { |
| 2374 | 13 | Field *field = table->field[i]; | |
| 2375 | |||
| 2376 | 13 | field->reset(); | |
| 2377 | |||
| 2378 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
13 | if (innobase_is_v_fld(field)) { |
| 2379 | /* Virtual column are not stored in InnoDB table, so | ||
| 2380 | skip it */ | ||
| 2381 | 2 | num_v++; | |
| 2382 | 2 | continue; | |
| 2383 | } | ||
| 2384 | |||
| 2385 | 11 | const dfield_t *df = dtuple_get_nth_field(row, i - num_v); | |
| 2386 | |||
| 2387 |
5/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 8 times.
|
11 | if (dfield_is_ext(df) || dfield_is_null(df)) { |
| 2388 | 3 | field->set_null(); | |
| 2389 | } else { | ||
| 2390 | 8 | field->set_notnull(); | |
| 2391 | |||
| 2392 | 8 | innobase_col_to_mysql(itab->get_col(i - num_v), | |
| 2393 | 8 | static_cast<const uchar *>(dfield_get_data(df)), | |
| 2394 | 8 | dfield_get_len(df), field); | |
| 2395 | } | ||
| 2396 | } | ||
| 2397 | 5 | } | |
| 2398 | |||
| 2399 | /** Resets table->record[0]. */ | ||
| 2400 | 35473 | void innobase_rec_reset(TABLE *table) /*!< in/out: MySQL table */ | |
| 2401 | { | ||
| 2402 | 35473 | uint n_fields = table->s->fields; | |
| 2403 | uint i; | ||
| 2404 | |||
| 2405 |
2/2✓ Branch 0 taken 270015 times.
✓ Branch 1 taken 35473 times.
|
305488 | for (i = 0; i < n_fields; i++) { |
| 2406 |
2/2✓ Branch 0 taken 269989 times.
✓ Branch 1 taken 26 times.
|
270015 | if (!table->field[i]->m_default_val_expr) { |
| 2407 | 269989 | table->field[i]->set_default(); | |
| 2408 | } else { | ||
| 2409 | 26 | table->field[i]->copy_data(table->default_values_offset()); | |
| 2410 | } | ||
| 2411 | } | ||
| 2412 | 35473 | } | |
| 2413 | |||
| 2414 | /** This function checks that index keys are sensible. | ||
| 2415 | @return 0 or error number */ | ||
| 2416 | 47715 | [[nodiscard]] static int innobase_check_index_keys( | |
| 2417 | const Alter_inplace_info *info, | ||
| 2418 | /*!< in: indexes to be created or dropped */ | ||
| 2419 | const dict_table_t *innodb_table) | ||
| 2420 | /*!< in: Existing indexes */ | ||
| 2421 | { | ||
| 2422 |
2/2✓ Branch 0 taken 7813 times.
✓ Branch 1 taken 47715 times.
|
55528 | for (uint key_num = 0; key_num < info->index_add_count; key_num++) { |
| 2423 | 7813 | const KEY &key = info->key_info_buffer[info->index_add_buffer[key_num]]; | |
| 2424 | |||
| 2425 | /* Check that the same index name does not appear | ||
| 2426 | twice in indexes to be created. */ | ||
| 2427 | |||
| 2428 |
2/2✓ Branch 0 taken 2223 times.
✓ Branch 1 taken 7813 times.
|
10036 | for (ulint i = 0; i < key_num; i++) { |
| 2429 | 2223 | const KEY &key2 = info->key_info_buffer[info->index_add_buffer[i]]; | |
| 2430 | |||
| 2431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2223 times.
|
2223 | if (0 == strcmp(key.name, key2.name)) { |
| 2432 | ✗ | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key.name); | |
| 2433 | |||
| 2434 | ✗ | return (ER_WRONG_NAME_FOR_INDEX); | |
| 2435 | } | ||
| 2436 | } | ||
| 2437 | |||
| 2438 | /* Check that the same index name does not already exist. */ | ||
| 2439 | |||
| 2440 | const dict_index_t *index; | ||
| 2441 | |||
| 2442 |
2/2✓ Branch 0 taken 12472 times.
✓ Branch 1 taken 7071 times.
|
19543 | for (index = innodb_table->first_index(); index; index = index->next()) { |
| 2443 |
6/6✓ Branch 0 taken 12470 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 742 times.
✓ Branch 3 taken 11728 times.
✓ Branch 4 taken 742 times.
✓ Branch 5 taken 11730 times.
|
12472 | if (index->is_committed() && !strcmp(key.name, index->name)) { |
| 2444 | 742 | break; | |
| 2445 | } | ||
| 2446 | } | ||
| 2447 | |||
| 2448 | /* Now we are in a situation where we have "ADD INDEX x" | ||
| 2449 | and an index by the same name already exists. We have 4 | ||
| 2450 | possible cases: | ||
| 2451 | 1. No further clauses for an index x are given. Should reject | ||
| 2452 | the operation. | ||
| 2453 | 2. "DROP INDEX x" is given. Should allow the operation. | ||
| 2454 | 3. "RENAME INDEX x TO y" is given. Should allow the operation. | ||
| 2455 | 4. "DROP INDEX x, RENAME INDEX x TO y" is given. Should allow | ||
| 2456 | the operation, since no name clash occurs. In this particular | ||
| 2457 | case MySQL cancels the operation without calling InnoDB | ||
| 2458 | methods. */ | ||
| 2459 | |||
| 2460 |
2/2✓ Branch 0 taken 742 times.
✓ Branch 1 taken 7071 times.
|
7813 | if (index) { |
| 2461 | /* If a key by the same name is being created and | ||
| 2462 | dropped, the name clash is OK. */ | ||
| 2463 |
2/2✓ Branch 0 taken 764 times.
✓ Branch 1 taken 8 times.
|
772 | for (uint i = 0; i < info->index_drop_count; i++) { |
| 2464 | 764 | const KEY *drop_key = info->index_drop_buffer[i]; | |
| 2465 | |||
| 2466 |
2/2✓ Branch 0 taken 734 times.
✓ Branch 1 taken 30 times.
|
764 | if (0 == strcmp(key.name, drop_key->name)) { |
| 2467 | 734 | goto name_ok; | |
| 2468 | } | ||
| 2469 | } | ||
| 2470 | |||
| 2471 | /* If a key by the same name is being created and | ||
| 2472 | renamed, the name clash is OK. E.g. | ||
| 2473 | ALTER TABLE t ADD INDEX i (col), RENAME INDEX i TO x | ||
| 2474 | where the index "i" exists prior to the ALTER command. | ||
| 2475 | In this case we: | ||
| 2476 | 1. rename the existing index from "i" to "x" | ||
| 2477 | 2. add the new index "i" */ | ||
| 2478 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | for (uint i = 0; i < info->index_rename_count; i++) { |
| 2479 | 8 | const KEY_PAIR *pair = &info->index_rename_buffer[i]; | |
| 2480 | |||
| 2481 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (0 == strcmp(key.name, pair->old_key->name)) { |
| 2482 | 8 | goto name_ok; | |
| 2483 | } | ||
| 2484 | } | ||
| 2485 | |||
| 2486 | ✗ | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key.name); | |
| 2487 | |||
| 2488 | ✗ | return (ER_WRONG_NAME_FOR_INDEX); | |
| 2489 | } | ||
| 2490 | |||
| 2491 | 7071 | name_ok: | |
| 2492 |
2/2✓ Branch 0 taken 11743 times.
✓ Branch 1 taken 7813 times.
|
19556 | for (ulint i = 0; i < key.user_defined_key_parts; i++) { |
| 2493 | 11743 | const KEY_PART_INFO &key_part1 = key.key_part[i]; | |
| 2494 | 11743 | const Field *field = key_part1.field; | |
| 2495 | ulint is_unsigned; | ||
| 2496 | |||
| 2497 |
3/4✓ Branch 0 taken 11743 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5592 times.
✓ Branch 3 taken 6151 times.
|
11743 | switch (get_innobase_type_from_mysql_type(&is_unsigned, field)) { |
| 2498 | 5592 | default: | |
| 2499 | 5592 | break; | |
| 2500 | 6151 | case DATA_INT: | |
| 2501 | case DATA_FLOAT: | ||
| 2502 | case DATA_DOUBLE: | ||
| 2503 | case DATA_DECIMAL: | ||
| 2504 | /* Check that MySQL does not try to | ||
| 2505 | create a column prefix index field on | ||
| 2506 | an inappropriate data type. */ | ||
| 2507 | |||
| 2508 |
2/4✓ Branch 0 taken 6151 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6151 times.
|
6151 | if (field->type() == MYSQL_TYPE_VARCHAR) { |
| 2509 | ✗ | if (key_part1.length >= | |
| 2510 | ✗ | field->pack_length() - field->get_length_bytes()) { | |
| 2511 | ✗ | break; | |
| 2512 | } | ||
| 2513 | } else { | ||
| 2514 |
4/6✓ Branch 0 taken 6151 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 6105 times.
✓ Branch 4 taken 6151 times.
✗ Branch 5 not taken.
|
6197 | if (key_part1.length >= field->pack_length() || |
| 2515 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | innobase_is_multi_value_fld(field)) { |
| 2516 | 6151 | break; | |
| 2517 | } | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | ✗ | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); | |
| 2521 | ✗ | return (ER_WRONG_KEY_COLUMN); | |
| 2522 | } | ||
| 2523 | |||
| 2524 | /* Check that the same column does not appear | ||
| 2525 | twice in the index. */ | ||
| 2526 | |||
| 2527 |
2/2✓ Branch 0 taken 13540 times.
✓ Branch 1 taken 11743 times.
|
25283 | for (ulint j = 0; j < i; j++) { |
| 2528 | 13540 | const KEY_PART_INFO &key_part2 = key.key_part[j]; | |
| 2529 | |||
| 2530 |
1/2✓ Branch 0 taken 13540 times.
✗ Branch 1 not taken.
|
13540 | if (key_part1.fieldnr != key_part2.fieldnr) { |
| 2531 | 13540 | continue; | |
| 2532 | } | ||
| 2533 | |||
| 2534 | ✗ | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); | |
| 2535 | ✗ | return (ER_WRONG_KEY_COLUMN); | |
| 2536 | } | ||
| 2537 | } | ||
| 2538 | } | ||
| 2539 | |||
| 2540 | 47715 | return (0); | |
| 2541 | } | ||
| 2542 | |||
| 2543 | /** Create index field definition for key part | ||
| 2544 | @param[in] altered_table MySQL table that is being altered, | ||
| 2545 | or NULL if a new clustered index | ||
| 2546 | is not being created | ||
| 2547 | @param[in] key_part MySQL key definition | ||
| 2548 | @param[in,out] index_field index field | ||
| 2549 | @param[in] new_clustered new cluster */ | ||
| 2550 | 60531 | static void innobase_create_index_field_def(const TABLE *altered_table, | |
| 2551 | const KEY_PART_INFO *key_part, | ||
| 2552 | ddl::Index_field *index_field, | ||
| 2553 | bool new_clustered) { | ||
| 2554 | const Field *field; | ||
| 2555 | ulint is_unsigned; | ||
| 2556 | ulint col_type; | ||
| 2557 | 60531 | ulint num_v = 0; | |
| 2558 | |||
| 2559 |
1/2✓ Branch 0 taken 60531 times.
✗ Branch 1 not taken.
|
60531 | DBUG_TRACE; |
| 2560 | |||
| 2561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60531 times.
|
60531 | ut_ad(key_part); |
| 2562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60531 times.
|
60531 | ut_ad(index_field); |
| 2563 | |||
| 2564 |
2/2✓ Branch 0 taken 53383 times.
✓ Branch 1 taken 7148 times.
|
60531 | field = |
| 2565 | 53383 | new_clustered ? altered_table->field[key_part->fieldnr] : key_part->field; | |
| 2566 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60531 times.
|
60531 | ut_a(field); |
| 2567 | |||
| 2568 |
2/2✓ Branch 0 taken 111609 times.
✓ Branch 1 taken 60531 times.
|
172140 | for (ulint i = 0; i < key_part->fieldnr; i++) { |
| 2569 |
4/4✓ Branch 0 taken 372 times.
✓ Branch 1 taken 111237 times.
✓ Branch 2 taken 277 times.
✓ Branch 3 taken 95 times.
|
111609 | if (innobase_is_v_fld(altered_table->field[i])) { |
| 2570 | 277 | num_v++; | |
| 2571 | } | ||
| 2572 | } | ||
| 2573 | |||
| 2574 |
1/2✓ Branch 0 taken 60531 times.
✗ Branch 1 not taken.
|
60531 | col_type = get_innobase_type_from_mysql_type(&is_unsigned, field); |
| 2575 | |||
| 2576 |
1/2✓ Branch 0 taken 60531 times.
✗ Branch 1 not taken.
|
60531 | index_field->m_is_multi_value = innobase_is_multi_value_fld(field); |
| 2577 |
3/4✓ Branch 0 taken 350 times.
✓ Branch 1 taken 60181 times.
✓ Branch 2 taken 350 times.
✗ Branch 3 not taken.
|
60531 | if (!field->stored_in_db && field->gcol_info) { |
| 2578 | 350 | index_field->m_is_v_col = true; | |
| 2579 | 350 | index_field->m_col_no = num_v; | |
| 2580 | } else { | ||
| 2581 | 60181 | index_field->m_is_v_col = false; | |
| 2582 | 60181 | index_field->m_col_no = key_part->fieldnr - num_v; | |
| 2583 | } | ||
| 2584 | 60531 | index_field->m_is_ascending = !(key_part->key_part_flag & HA_REVERSE_SORT); | |
| 2585 | |||
| 2586 | /* No prefix index on multi-value field */ | ||
| 2587 |
6/6✓ Branch 0 taken 60433 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 59720 times.
✓ Branch 3 taken 713 times.
✓ Branch 4 taken 1077 times.
✓ Branch 5 taken 59454 times.
|
180684 | if (!index_field->m_is_multi_value && |
| 2588 | 60433 | (DATA_LARGE_MTYPE(col_type) || | |
| 2589 |
3/4✓ Branch 0 taken 59720 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5492 times.
✓ Branch 3 taken 54228 times.
|
59720 | (key_part->length < field->pack_length() && |
| 2590 |
3/4✓ Branch 0 taken 5492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5410 times.
✓ Branch 3 taken 82 times.
|
5492 | field->type() != MYSQL_TYPE_VARCHAR) || |
| 2591 |
3/4✓ Branch 0 taken 59638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5410 times.
✓ Branch 3 taken 54228 times.
|
59638 | (field->type() == MYSQL_TYPE_VARCHAR && |
| 2592 |
4/6✓ Branch 0 taken 5410 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5410 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 282 times.
✓ Branch 5 taken 5128 times.
|
5410 | key_part->length < field->pack_length() - field->get_length_bytes()))) { |
| 2593 | 1077 | index_field->m_prefix_len = key_part->length; | |
| 2594 | } else { | ||
| 2595 | 59454 | index_field->m_prefix_len = 0; | |
| 2596 | } | ||
| 2597 | 60531 | } | |
| 2598 | |||
| 2599 | template <typename Index> | ||
| 2600 | const dd::Index *get_dd_index(const Index *index); | ||
| 2601 | |||
| 2602 | template <> | ||
| 2603 | 105 | const dd::Index *get_dd_index<dd::Index>(const dd::Index *dd_index) { | |
| 2604 | 105 | return dd_index; | |
| 2605 | } | ||
| 2606 | |||
| 2607 | template <> | ||
| 2608 | ✗ | const dd::Index *get_dd_index<dd::Partition_index>( | |
| 2609 | const dd::Partition_index *dd_index) { | ||
| 2610 | ✗ | return (dd_index != nullptr) ? &dd_index->index() : nullptr; | |
| 2611 | } | ||
| 2612 | |||
| 2613 | /** Create index definition for key | ||
| 2614 | @param[in] altered_table MySQL table that is being altered | ||
| 2615 | @param[in] new_dd_tab New dd table | ||
| 2616 | @param[in] keys Key definitions | ||
| 2617 | @param[in] key_number MySQL key number | ||
| 2618 | @param[in] new_clustered true if generating a new clustered index | ||
| 2619 | on the table | ||
| 2620 | @param[in] key_clustered true if this is the new clustered index | ||
| 2621 | @param[out] index_def Index definition | ||
| 2622 | @param[in] heap heap where memory is allocated */ | ||
| 2623 | template <typename Table> | ||
| 2624 | 77380 | static void innobase_create_index_def(const TABLE *altered_table, | |
| 2625 | const Table *new_dd_tab, const KEY *keys, | ||
| 2626 | ulint key_number, bool new_clustered, | ||
| 2627 | bool key_clustered, | ||
| 2628 | ddl::Index_defn *index_def, | ||
| 2629 | mem_heap_t *heap) { | ||
| 2630 | ulint i; | ||
| 2631 | 77380 | const KEY *key = &keys[key_number]; | |
| 2632 | 77380 | ulint n_fields = key->user_defined_key_parts; | |
| 2633 | |||
| 2634 |
1/2✓ Branch 0 taken 38690 times.
✗ Branch 1 not taken.
|
77380 | DBUG_TRACE; |
| 2635 |
3/4✓ Branch 0 taken 23718 times.
✓ Branch 1 taken 14972 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23718 times.
|
77380 | assert(!key_clustered || new_clustered); |
| 2636 | |||
| 2637 | 77380 | index_def->m_fields = static_cast<ddl::Index_field *>( | |
| 2638 |
1/2✓ Branch 0 taken 38690 times.
✗ Branch 1 not taken.
|
77380 | mem_heap_alloc(heap, n_fields * sizeof *index_def->m_fields)); |
| 2639 | |||
| 2640 | 77380 | index_def->m_parser = nullptr; | |
| 2641 | 77380 | index_def->m_is_ngram = false; | |
| 2642 | 77380 | index_def->m_key_number = key_number; | |
| 2643 | 77380 | index_def->m_n_fields = n_fields; | |
| 2644 |
1/2✓ Branch 0 taken 38690 times.
✗ Branch 1 not taken.
|
77380 | index_def->m_name = mem_heap_strdup(heap, key->name); |
| 2645 | 77380 | index_def->m_rebuild = new_clustered; | |
| 2646 | |||
| 2647 | /* If this is a spatial index, we need to fetch the SRID */ | ||
| 2648 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 38585 times.
|
77380 | if (key->flags & HA_SPATIAL) { |
| 2649 | 210 | ulint dd_key_num = | |
| 2650 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 47 times.
|
210 | key_number + ((altered_table->s->primary_key == MAX_KEY) ? 1 : 0); |
| 2651 | |||
| 2652 | 210 | const auto *dd_index_auto = | |
| 2653 | 210 | (index_def->m_key_number != ULINT_UNDEFINED) | |
| 2654 |
3/6✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 105 times.
✗ Branch 5 not taken.
|
210 | ? const_cast<const Table *>(new_dd_tab)->indexes()[dd_key_num] |
| 2655 | : nullptr; | ||
| 2656 | |||
| 2657 |
1/2✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
|
210 | const dd::Index *dd_index = get_dd_index(dd_index_auto); |
| 2658 | |||
| 2659 |
1/2✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
|
210 | if (dd_index != nullptr) { |
| 2660 |
2/4✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
|
210 | ut_ad(dd_index->name() == key->name); |
| 2661 | /* Spatial index indexes on only one column */ | ||
| 2662 | size_t geom_col_idx; | ||
| 2663 |
2/4✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
|
210 | for (geom_col_idx = 0; geom_col_idx < dd_index->elements().size(); |
| 2664 | ++geom_col_idx) { | ||
| 2665 |
5/10✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 105 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 105 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 105 times.
✗ Branch 9 not taken.
|
210 | if (!dd_index->elements()[geom_col_idx]->column().is_se_hidden()) break; |
| 2666 | } | ||
| 2667 |
3/6✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 105 times.
✗ Branch 5 not taken.
|
210 | const dd::Column &col = dd_index->elements()[geom_col_idx]->column(); |
| 2668 |
1/2✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
|
210 | bool has_value = col.srs_id().has_value(); |
| 2669 | 210 | index_def->m_srid_is_valid = has_value; | |
| 2670 |
4/6✓ Branch 0 taken 96 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 96 times.
✗ Branch 5 not taken.
|
210 | index_def->m_srid = has_value ? col.srs_id().value() : 0; |
| 2671 | } | ||
| 2672 | } | ||
| 2673 | |||
| 2674 |
2/2✓ Branch 0 taken 23718 times.
✓ Branch 1 taken 14972 times.
|
77380 | if (key_clustered) { |
| 2675 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23718 times.
|
47436 | assert(!(key->flags & (HA_FULLTEXT | HA_SPATIAL))); |
| 2676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23718 times.
|
47436 | assert(key->flags & HA_NOSAME); |
| 2677 | 47436 | index_def->m_ind_type = DICT_CLUSTERED | DICT_UNIQUE; | |
| 2678 |
2/2✓ Branch 0 taken 469 times.
✓ Branch 1 taken 14503 times.
|
29944 | } else if (key->flags & HA_FULLTEXT) { |
| 2679 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
|
938 | assert(!(key->flags & (HA_SPATIAL | HA_NOSAME))); |
| 2680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
|
938 | assert(!(key->flags & HA_KEYFLAG_MASK & |
| 2681 | ~(HA_FULLTEXT | HA_PACK_KEY | HA_BINARY_PACK_KEY))); | ||
| 2682 | 938 | index_def->m_ind_type = DICT_FTS; | |
| 2683 | |||
| 2684 | /* Set plugin parser */ | ||
| 2685 | /* Note: key->parser is only parser name, | ||
| 2686 | we need to get parser from altered_table instead */ | ||
| 2687 |
2/2✓ Branch 0 taken 239 times.
✓ Branch 1 taken 230 times.
|
938 | if (key->flags & HA_USES_PARSER) { |
| 2688 |
1/2✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
|
2304 | for (ulint j = 0; j < altered_table->s->keys; j++) { |
| 2689 |
2/2✓ Branch 0 taken 239 times.
✓ Branch 1 taken 913 times.
|
2304 | if (ut_strcmp(altered_table->key_info[j].name, key->name) == 0) { |
| 2690 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
|
478 | ut_ad(altered_table->key_info[j].flags & HA_USES_PARSER); |
| 2691 | |||
| 2692 | 478 | plugin_ref parser = altered_table->key_info[j].parser; | |
| 2693 | 478 | index_def->m_parser = | |
| 2694 | 478 | static_cast<st_mysql_ftparser *>(plugin_decl(parser)->info); | |
| 2695 | |||
| 2696 | 478 | index_def->m_is_ngram = | |
| 2697 | 478 | strncmp(plugin_name(parser)->str, FTS_NGRAM_PARSER_NAME, | |
| 2698 | 478 | plugin_name(parser)->length) == 0; | |
| 2699 | |||
| 2700 | 478 | break; | |
| 2701 | } | ||
| 2702 | } | ||
| 2703 | |||
| 2704 |
3/4✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 238 times.
|
478 | DBUG_EXECUTE_IF("fts_instrument_use_default_parser", |
| 2705 | index_def->m_parser = &fts_default_parser;); | ||
| 2706 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
|
478 | ut_ad(index_def->m_parser); |
| 2707 | } | ||
| 2708 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 14398 times.
|
29006 | } else if (key->flags & HA_SPATIAL) { |
| 2709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
210 | assert(!(key->flags & HA_NOSAME)); |
| 2710 | 210 | index_def->m_ind_type = DICT_SPATIAL; | |
| 2711 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
210 | ut_ad(n_fields == 1); |
| 2712 | 210 | ulint num_v = 0; | |
| 2713 | |||
| 2714 | /* Need to count the virtual fields before this spatial | ||
| 2715 | indexed field */ | ||
| 2716 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 105 times.
|
468 | for (ulint i = 0; i < key->key_part->fieldnr; i++) { |
| 2717 |
4/4✓ Branch 0 taken 17 times.
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 3 times.
|
258 | if (innobase_is_v_fld(altered_table->field[i])) { |
| 2718 | 28 | num_v++; | |
| 2719 | } | ||
| 2720 | } | ||
| 2721 | 210 | index_def->m_fields[0].m_col_no = key->key_part[0].fieldnr - num_v; | |
| 2722 | 210 | index_def->m_fields[0].m_prefix_len = 0; | |
| 2723 | 210 | index_def->m_fields[0].m_is_v_col = false; | |
| 2724 | |||
| 2725 | /* Currently only ascending order is supported in spatial | ||
| 2726 | index. */ | ||
| 2727 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
210 | ut_ad(!(key->key_part[0].key_part_flag & HA_REVERSE_SORT)); |
| 2728 | 210 | index_def->m_fields[0].m_is_ascending = true; | |
| 2729 | |||
| 2730 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
210 | if (!key->key_part[0].field->stored_in_db && |
| 2731 | ✗ | key->key_part[0].field->gcol_info) { | |
| 2732 | ✗ | index_def->m_fields[0].m_is_v_col = true; | |
| 2733 | /* Currently, the spatial index cannot be created | ||
| 2734 | on virtual columns. It is blocked in server | ||
| 2735 | layer */ | ||
| 2736 | ✗ | ut_d(ut_error); | |
| 2737 | } else { | ||
| 2738 | 210 | index_def->m_fields[0].m_is_v_col = false; | |
| 2739 | } | ||
| 2740 | } else { | ||
| 2741 | 28796 | index_def->m_ind_type = (key->flags & HA_NOSAME) ? DICT_UNIQUE : 0; | |
| 2742 | } | ||
| 2743 | |||
| 2744 |
2/2✓ Branch 0 taken 38585 times.
✓ Branch 1 taken 105 times.
|
77380 | if (!(key->flags & HA_SPATIAL)) { |
| 2745 |
2/2✓ Branch 0 taken 60531 times.
✓ Branch 1 taken 38585 times.
|
198232 | for (i = 0; i < n_fields; i++) { |
| 2746 | 121062 | innobase_create_index_field_def(altered_table, &key->key_part[i], | |
| 2747 |
1/2✓ Branch 0 taken 60531 times.
✗ Branch 1 not taken.
|
121062 | &index_def->m_fields[i], new_clustered); |
| 2748 | |||
| 2749 |
2/2✓ Branch 0 taken 350 times.
✓ Branch 1 taken 60181 times.
|
121062 | if (index_def->m_fields[i].m_is_v_col) { |
| 2750 | 700 | index_def->m_ind_type |= DICT_VIRTUAL; | |
| 2751 | } | ||
| 2752 | |||
| 2753 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 60433 times.
|
121062 | if (index_def->m_fields[i].m_is_multi_value) { |
| 2754 | 196 | index_def->m_ind_type |= DICT_MULTI_VALUE; | |
| 2755 | } | ||
| 2756 | } | ||
| 2757 | } | ||
| 2758 | 77380 | } | |
| 2759 | |||
| 2760 | /** Check whether the table has the FTS_DOC_ID column | ||
| 2761 | @return whether there exists an FTS_DOC_ID column */ | ||
| 2762 | 491 | bool innobase_fts_check_doc_id_col( | |
| 2763 | const dict_table_t *table, /*!< in: InnoDB table with | ||
| 2764 | fulltext index */ | ||
| 2765 | const TABLE *altered_table, | ||
| 2766 | /*!< in: MySQL table with | ||
| 2767 | fulltext index */ | ||
| 2768 | ulint *fts_doc_col_no, | ||
| 2769 | /*!< out: The column number for | ||
| 2770 | Doc ID, or ULINT_UNDEFINED | ||
| 2771 | if it is of wrong type */ | ||
| 2772 | ulint *num_v) /*!< out: number of virtual column */ | ||
| 2773 | { | ||
| 2774 | 491 | *fts_doc_col_no = ULINT_UNDEFINED; | |
| 2775 | |||
| 2776 | 491 | const uint n_cols = altered_table->s->fields; | |
| 2777 | ulint i; | ||
| 2778 | |||
| 2779 | 491 | *num_v = 0; | |
| 2780 | |||
| 2781 |
2/2✓ Branch 0 taken 2901 times.
✓ Branch 1 taken 454 times.
|
3355 | for (i = 0; i < n_cols; i++) { |
| 2782 | 2901 | const Field *field = altered_table->field[i]; | |
| 2783 | |||
| 2784 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2895 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
2901 | if (innobase_is_v_fld(field)) { |
| 2785 | 4 | (*num_v)++; | |
| 2786 | } | ||
| 2787 | |||
| 2788 |
2/2✓ Branch 0 taken 2864 times.
✓ Branch 1 taken 37 times.
|
2901 | if (my_strcasecmp(system_charset_info, field->field_name, |
| 2789 | FTS_DOC_ID_COL_NAME)) { | ||
| 2790 | 2864 | continue; | |
| 2791 | } | ||
| 2792 | |||
| 2793 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (strcmp(field->field_name, FTS_DOC_ID_COL_NAME)) { |
| 2794 | ✗ | my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name); | |
| 2795 | 37 | } else if (field->type() != MYSQL_TYPE_LONGLONG || | |
| 2796 |
2/4✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
37 | field->pack_length() != 8 || field->is_nullable() || |
| 2797 |
6/10✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 36 times.
|
74 | !field->is_flag_set(UNSIGNED_FLAG) || innobase_is_v_fld(field)) { |
| 2798 | 1 | my_error(ER_INNODB_FT_WRONG_DOCID_COLUMN, MYF(0), field->field_name); | |
| 2799 | } else { | ||
| 2800 | 36 | *fts_doc_col_no = i - *num_v; | |
| 2801 | } | ||
| 2802 | |||
| 2803 | 37 | return (true); | |
| 2804 | } | ||
| 2805 | |||
| 2806 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
|
454 | if (!table) { |
| 2807 | ✗ | return (false); | |
| 2808 | } | ||
| 2809 | |||
| 2810 | /* Not to count the virtual columns */ | ||
| 2811 | 454 | i -= *num_v; | |
| 2812 | |||
| 2813 |
2/2✓ Branch 0 taken 332 times.
✓ Branch 1 taken 122 times.
|
454 | for (; i + DATA_N_SYS_COLS < (uint)table->n_cols; i++) { |
| 2814 | 332 | const char *name = table->get_col_name(i); | |
| 2815 | |||
| 2816 |
1/2✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
|
332 | if (strcmp(name, FTS_DOC_ID_COL_NAME) == 0) { |
| 2817 | #ifdef UNIV_DEBUG | ||
| 2818 | const dict_col_t *col; | ||
| 2819 | |||
| 2820 | 332 | col = table->get_col(i); | |
| 2821 | |||
| 2822 | /* Because the FTS_DOC_ID does not exist in | ||
| 2823 | the MySQL data dictionary, this must be the | ||
| 2824 | internally created FTS_DOC_ID column. */ | ||
| 2825 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
|
332 | ut_ad(col->mtype == DATA_INT); |
| 2826 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
|
332 | ut_ad(col->len == 8); |
| 2827 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
|
332 | ut_ad(col->prtype & DATA_NOT_NULL); |
| 2828 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
|
332 | ut_ad(col->prtype & DATA_UNSIGNED); |
| 2829 | #endif /* UNIV_DEBUG */ | ||
| 2830 | 332 | *fts_doc_col_no = i; | |
| 2831 | 332 | return (true); | |
| 2832 | } | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | 122 | return (false); | |
| 2836 | } | ||
| 2837 | |||
| 2838 | /** Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME | ||
| 2839 | on the Doc ID column. | ||
| 2840 | @return the status of the FTS_DOC_ID index */ | ||
| 2841 | 6653 | enum fts_doc_id_index_enum innobase_fts_check_doc_id_index( | |
| 2842 | const dict_table_t *table, /*!< in: table definition */ | ||
| 2843 | const TABLE *altered_table, /*!< in: MySQL table | ||
| 2844 | that is being altered */ | ||
| 2845 | ulint *fts_doc_col_no) /*!< out: The column number for | ||
| 2846 | Doc ID, or ULINT_UNDEFINED | ||
| 2847 | if it is being created in | ||
| 2848 | ha_alter_info */ | ||
| 2849 | { | ||
| 2850 | const dict_index_t *index; | ||
| 2851 | const dict_field_t *field; | ||
| 2852 | |||
| 2853 |
2/2✓ Branch 0 taken 489 times.
✓ Branch 1 taken 6164 times.
|
6653 | if (altered_table) { |
| 2854 | /* Check if a unique index with the name of | ||
| 2855 | FTS_DOC_ID_INDEX_NAME is being created. */ | ||
| 2856 | |||
| 2857 |
2/2✓ Branch 0 taken 1773 times.
✓ Branch 1 taken 473 times.
|
2246 | for (uint i = 0; i < altered_table->s->keys; i++) { |
| 2858 | 1773 | const KEY &key = altered_table->key_info[i]; | |
| 2859 | |||
| 2860 |
2/2✓ Branch 0 taken 1757 times.
✓ Branch 1 taken 16 times.
|
1773 | if (innobase_strcasecmp(key.name, FTS_DOC_ID_INDEX_NAME)) { |
| 2861 | 1757 | continue; | |
| 2862 | } | ||
| 2863 | |||
| 2864 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if ((key.flags & HA_NOSAME) && |
| 2865 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | key.user_defined_key_parts == 1 |
| 2866 | /* For now, we do not allow a descending index, | ||
| 2867 | because fts_doc_fetch_by_doc_id() uses the | ||
| 2868 | InnoDB SQL interpreter to look up FTS_DOC_ID. */ | ||
| 2869 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | && !(key.key_part[0].key_part_flag & HA_REVERSE_SORT) && |
| 2870 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | !strcmp(key.name, FTS_DOC_ID_INDEX_NAME) && |
| 2871 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | !strcmp(key.key_part[0].field->field_name, FTS_DOC_ID_COL_NAME)) { |
| 2872 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (fts_doc_col_no) { |
| 2873 | 16 | *fts_doc_col_no = ULINT_UNDEFINED; | |
| 2874 | } | ||
| 2875 | 16 | return (FTS_EXIST_DOC_ID_INDEX); | |
| 2876 | } else { | ||
| 2877 | ✗ | return (FTS_INCORRECT_DOC_ID_INDEX); | |
| 2878 | } | ||
| 2879 | } | ||
| 2880 | } | ||
| 2881 | |||
| 2882 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6637 times.
|
6637 | if (!table) { |
| 2883 | ✗ | return (FTS_NOT_EXIST_DOC_ID_INDEX); | |
| 2884 | } | ||
| 2885 | |||
| 2886 |
2/2✓ Branch 0 taken 16228 times.
✓ Branch 1 taken 137 times.
|
16365 | for (index = table->first_index(); index; index = index->next()) { |
| 2887 | /* Check if there exists a unique index with the name of | ||
| 2888 | FTS_DOC_ID_INDEX_NAME */ | ||
| 2889 |
2/2✓ Branch 0 taken 9728 times.
✓ Branch 1 taken 6500 times.
|
16228 | if (innobase_strcasecmp(index->name, FTS_DOC_ID_INDEX_NAME)) { |
| 2890 | 9728 | continue; | |
| 2891 | } | ||
| 2892 | |||
| 2893 | 6500 | if (!dict_index_is_unique(index) || | |
| 2894 |
1/2✓ Branch 0 taken 6500 times.
✗ Branch 1 not taken.
|
6500 | dict_index_get_n_unique(index) > 1 |
| 2895 | /* For now, we do not allow a descending index, | ||
| 2896 | because fts_doc_fetch_by_doc_id() uses the | ||
| 2897 | InnoDB SQL interpreter to look up FTS_DOC_ID. */ | ||
| 2898 |
3/6✓ Branch 0 taken 6500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6500 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6500 times.
|
19500 | || !index->get_field(0)->is_ascending || |
| 2899 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6500 times.
|
6500 | strcmp(index->name, FTS_DOC_ID_INDEX_NAME)) { |
| 2900 | ✗ | return (FTS_INCORRECT_DOC_ID_INDEX); | |
| 2901 | } | ||
| 2902 | |||
| 2903 | /* Check whether the index has FTS_DOC_ID as its | ||
| 2904 | first column */ | ||
| 2905 | 6500 | field = index->get_field(0); | |
| 2906 | |||
| 2907 | /* The column would be of a BIGINT data type */ | ||
| 2908 | 6500 | if (strcmp(field->name, FTS_DOC_ID_COL_NAME) == 0 && | |
| 2909 |
2/4✓ Branch 0 taken 6500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6500 times.
✗ Branch 3 not taken.
|
6500 | field->col->mtype == DATA_INT && field->col->len == 8 && |
| 2910 |
4/8✓ Branch 0 taken 6500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6500 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6500 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6500 times.
✗ Branch 7 not taken.
|
13000 | field->col->prtype & DATA_NOT_NULL && !field->col->is_virtual()) { |
| 2911 |
2/2✓ Branch 0 taken 599 times.
✓ Branch 1 taken 5901 times.
|
6500 | if (fts_doc_col_no) { |
| 2912 | 599 | *fts_doc_col_no = dict_col_get_no(field->col); | |
| 2913 | } | ||
| 2914 | 6500 | return (FTS_EXIST_DOC_ID_INDEX); | |
| 2915 | } else { | ||
| 2916 | ✗ | return (FTS_INCORRECT_DOC_ID_INDEX); | |
| 2917 | } | ||
| 2918 | } | ||
| 2919 | |||
| 2920 | /* Not found */ | ||
| 2921 | 137 | return (FTS_NOT_EXIST_DOC_ID_INDEX); | |
| 2922 | } | ||
| 2923 | /** Check whether the table has a unique index with FTS_DOC_ID_INDEX_NAME | ||
| 2924 | on the Doc ID column in MySQL create index definition. | ||
| 2925 | @return FTS_EXIST_DOC_ID_INDEX if there exists the FTS_DOC_ID index, | ||
| 2926 | FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */ | ||
| 2927 | 856 | enum fts_doc_id_index_enum innobase_fts_check_doc_id_index_in_def( | |
| 2928 | ulint n_key, /*!< in: Number of keys */ | ||
| 2929 | const KEY *key_info) /*!< in: Key definition */ | ||
| 2930 | { | ||
| 2931 | /* Check whether there is a "FTS_DOC_ID_INDEX" in the to be built index | ||
| 2932 | list */ | ||
| 2933 |
2/2✓ Branch 0 taken 1590 times.
✓ Branch 1 taken 848 times.
|
2438 | for (ulint j = 0; j < n_key; j++) { |
| 2934 | 1590 | const KEY *key = &key_info[j]; | |
| 2935 | |||
| 2936 |
2/2✓ Branch 0 taken 1582 times.
✓ Branch 1 taken 8 times.
|
1590 | if (innobase_strcasecmp(key->name, FTS_DOC_ID_INDEX_NAME)) { |
| 2937 | 1582 | continue; | |
| 2938 | } | ||
| 2939 | |||
| 2940 | /* Do a check on FTS DOC ID_INDEX, it must be unique, | ||
| 2941 | named as "FTS_DOC_ID_INDEX" and on column "FTS_DOC_ID" */ | ||
| 2942 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (!(key->flags & HA_NOSAME) || |
| 2943 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | key->user_defined_key_parts != 1 |
| 2944 | /* For now, we do not allow a descending index, | ||
| 2945 | because fts_doc_fetch_by_doc_id() uses the | ||
| 2946 | InnoDB SQL interpreter to look up FTS_DOC_ID. */ | ||
| 2947 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | || (key->key_part[0].key_part_flag & HA_REVERSE_SORT) || |
| 2948 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | strcmp(key->name, FTS_DOC_ID_INDEX_NAME) || |
| 2949 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | strcmp(key->key_part[0].field->field_name, FTS_DOC_ID_COL_NAME)) { |
| 2950 | ✗ | return (FTS_INCORRECT_DOC_ID_INDEX); | |
| 2951 | } | ||
| 2952 | |||
| 2953 | 8 | return (FTS_EXIST_DOC_ID_INDEX); | |
| 2954 | } | ||
| 2955 | |||
| 2956 | 848 | return (FTS_NOT_EXIST_DOC_ID_INDEX); | |
| 2957 | } | ||
| 2958 | |||
| 2959 | /** Create an index table where indexes are ordered as follows: | ||
| 2960 | |||
| 2961 | IF a new primary key is defined for the table THEN | ||
| 2962 | |||
| 2963 | 1) New primary key | ||
| 2964 | 2) The remaining keys in key_info | ||
| 2965 | |||
| 2966 | ELSE | ||
| 2967 | |||
| 2968 | 1) All new indexes in the order they arrive from MySQL | ||
| 2969 | |||
| 2970 | ENDIF | ||
| 2971 | |||
| 2972 | @return key definitions */ | ||
| 2973 | template <typename Table> | ||
| 2974 | [[nodiscard]] static MY_ATTRIBUTE((malloc)) ddl::Index_defn | ||
| 2975 | 71520 | *innobase_create_key_defs(mem_heap_t *heap, | |
| 2976 | /*!< in/out: memory heap where space for key | ||
| 2977 | definitions are allocated */ | ||
| 2978 | const Alter_inplace_info *ha_alter_info, | ||
| 2979 | /*!< in: alter operation */ | ||
| 2980 | const TABLE *altered_table, | ||
| 2981 | /*!< in: MySQL table that is being altered */ | ||
| 2982 | const Table *new_dd_table, | ||
| 2983 | /*!< in: new dd table */ | ||
| 2984 | ulint &n_add, | ||
| 2985 | /*!< in/out: number of indexes to be created */ | ||
| 2986 | ulint &n_fts_add, | ||
| 2987 | /*!< out: number of FTS indexes to be created */ | ||
| 2988 | bool got_default_clust, | ||
| 2989 | /*!< in: whether the table lacks a primary key */ | ||
| 2990 | ulint &fts_doc_id_col, | ||
| 2991 | /*!< in: The column number for Doc ID */ | ||
| 2992 | bool &add_fts_doc_id, | ||
| 2993 | /*!< in: whether we need to add new DOC ID | ||
| 2994 | column for FTS index */ | ||
| 2995 | bool &add_fts_doc_idx, | ||
| 2996 | /*!< in: whether we need to add new DOC ID | ||
| 2997 | index for FTS index */ | ||
| 2998 | const TABLE *table, bool is_file_per_table) | ||
| 2999 | /*!<in: old_table MySQL table as it is before the ALTER operation */ | ||
| 3000 | { | ||
| 3001 | ddl::Index_defn *indexdef; | ||
| 3002 | ddl::Index_defn *index_defs; | ||
| 3003 | bool new_primary; | ||
| 3004 | 71520 | const uint *const add = ha_alter_info->index_add_buffer; | |
| 3005 | 71520 | const KEY *const key_info = ha_alter_info->key_info_buffer; | |
| 3006 | |||
| 3007 |
1/2✓ Branch 0 taken 35760 times.
✗ Branch 1 not taken.
|
71520 | DBUG_TRACE; |
| 3008 |
3/4✓ Branch 0 taken 122 times.
✓ Branch 1 taken 35638 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 122 times.
|
71520 | assert(!add_fts_doc_id || add_fts_doc_idx); |
| 3009 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | assert(ha_alter_info->index_add_count == n_add); |
| 3010 | |||
| 3011 | /* If there is a primary key, it is always the first index | ||
| 3012 | defined for the innodb_table. */ | ||
| 3013 | |||
| 3014 |
5/6✓ Branch 0 taken 7544 times.
✓ Branch 1 taken 28216 times.
✓ Branch 2 taken 7544 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1201 times.
✓ Branch 5 taken 6343 times.
|
71520 | new_primary = n_add > 0 && !my_strcasecmp(system_charset_info, |
| 3015 | key_info[*add].name, "PRIMARY"); | ||
| 3016 | 71520 | n_fts_add = 0; | |
| 3017 | |||
| 3018 | /* If there is a UNIQUE INDEX consisting entirely of NOT NULL | ||
| 3019 | columns and if the index does not contain column prefix(es) | ||
| 3020 | (only prefix/part of the column is indexed), MySQL will treat the | ||
| 3021 | index as a PRIMARY KEY unless the table already has one. */ | ||
| 3022 | |||
| 3023 |
4/6✓ Branch 0 taken 10611 times.
✓ Branch 1 taken 25149 times.
✓ Branch 2 taken 10611 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35760 times.
|
71520 | ut_ad(altered_table->s->primary_key == 0 || |
| 3024 | altered_table->s->primary_key == MAX_KEY); | ||
| 3025 | |||
| 3026 |
4/4✓ Branch 0 taken 11550 times.
✓ Branch 1 taken 24210 times.
✓ Branch 2 taken 11023 times.
✓ Branch 3 taken 527 times.
|
71520 | if (got_default_clust && !new_primary) { |
| 3027 | 22046 | new_primary = (altered_table->s->primary_key != MAX_KEY); | |
| 3028 | } | ||
| 3029 | |||
| 3030 | 71520 | const bool rebuild = | |
| 3031 |
6/6✓ Branch 0 taken 34147 times.
✓ Branch 1 taken 1613 times.
✓ Branch 2 taken 34025 times.
✓ Branch 3 taken 122 times.
✓ Branch 4 taken 28732 times.
✓ Branch 5 taken 5293 times.
|
139570 | new_primary || add_fts_doc_id || |
| 3032 | 68050 | innobase_need_rebuild(ha_alter_info, table, is_file_per_table); | |
| 3033 | |||
| 3034 | /* Reserve one more space if new_primary is true, and we might | ||
| 3035 | need to add the FTS_DOC_ID_INDEX */ | ||
| 3036 | 143040 | indexdef = index_defs = static_cast<ddl::Index_defn *>(mem_heap_alloc( | |
| 3037 | heap, sizeof *indexdef * | ||
| 3038 |
1/2✓ Branch 0 taken 35760 times.
✗ Branch 1 not taken.
|
71520 | (ha_alter_info->key_count + rebuild + got_default_clust))); |
| 3039 | |||
| 3040 |
2/2✓ Branch 0 taken 30467 times.
✓ Branch 1 taken 5293 times.
|
71520 | if (rebuild) { |
| 3041 | ulint primary_key_number; | ||
| 3042 | |||
| 3043 |
2/2✓ Branch 0 taken 1613 times.
✓ Branch 1 taken 28854 times.
|
60934 | if (new_primary) { |
| 3044 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1613 times.
|
3226 | if (n_add == 0) { |
| 3045 | ✗ | assert(got_default_clust); | |
| 3046 | ✗ | assert(altered_table->s->primary_key == 0); | |
| 3047 | ✗ | primary_key_number = 0; | |
| 3048 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 1527 times.
|
3226 | } else if (ha_alter_info->handler_flags & |
| 3049 | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) { | ||
| 3050 | 172 | primary_key_number = altered_table->s->primary_key; | |
| 3051 | } else { | ||
| 3052 | 3054 | primary_key_number = *add; | |
| 3053 | } | ||
| 3054 |
2/2✓ Branch 0 taken 6749 times.
✓ Branch 1 taken 22105 times.
|
57708 | } else if (got_default_clust) { |
| 3055 | /* Create the GEN_CLUST_INDEX */ | ||
| 3056 | 13498 | ddl::Index_defn *index_def = indexdef++; | |
| 3057 | |||
| 3058 | 13498 | index_def->m_fields = nullptr; | |
| 3059 | 13498 | index_def->m_n_fields = 0; | |
| 3060 | 13498 | index_def->m_ind_type = DICT_CLUSTERED; | |
| 3061 | 13498 | index_def->m_name = innobase_index_reserve_name; | |
| 3062 | 13498 | index_def->m_rebuild = true; | |
| 3063 | 13498 | index_def->m_key_number = std::numeric_limits<size_t>::max(); | |
| 3064 | 13498 | index_def->m_is_ngram = false; | |
| 3065 | 13498 | primary_key_number = ULINT_UNDEFINED; | |
| 3066 | 13498 | goto created_clustered; | |
| 3067 | } else { | ||
| 3068 | 44210 | primary_key_number = 0; | |
| 3069 | } | ||
| 3070 | |||
| 3071 | /* Create the PRIMARY key index definition */ | ||
| 3072 |
1/2✓ Branch 0 taken 23718 times.
✗ Branch 1 not taken.
|
47436 | innobase_create_index_def(altered_table, new_dd_table, key_info, |
| 3073 | primary_key_number, true, true, indexdef++, heap); | ||
| 3074 | |||
| 3075 | 60934 | created_clustered: | |
| 3076 | 60934 | n_add = 1; | |
| 3077 | |||
| 3078 |
2/2✓ Branch 0 taken 33184 times.
✓ Branch 1 taken 30467 times.
|
127302 | for (ulint i = 0; i < ha_alter_info->key_count; i++) { |
| 3079 |
2/2✓ Branch 0 taken 23718 times.
✓ Branch 1 taken 9466 times.
|
66368 | if (i == primary_key_number) { |
| 3080 | 47436 | continue; | |
| 3081 | } | ||
| 3082 | /* Copy the index definitions. */ | ||
| 3083 |
1/2✓ Branch 0 taken 9466 times.
✗ Branch 1 not taken.
|
18932 | innobase_create_index_def(altered_table, new_dd_table, key_info, i, true, |
| 3084 | false, indexdef, heap); | ||
| 3085 | |||
| 3086 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 9343 times.
|
18932 | if (indexdef->m_ind_type & DICT_FTS) { |
| 3087 | 246 | n_fts_add++; | |
| 3088 | } | ||
| 3089 | |||
| 3090 | 18932 | indexdef++; | |
| 3091 | 18932 | n_add++; | |
| 3092 | } | ||
| 3093 | |||
| 3094 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 30344 times.
|
60934 | if (n_fts_add > 0) { |
| 3095 | 246 | ulint num_v = 0; | |
| 3096 | |||
| 3097 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
|
248 | if (!add_fts_doc_id && |
| 3098 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
2 | !innobase_fts_check_doc_id_col(nullptr, altered_table, |
| 3099 | &fts_doc_id_col, &num_v)) { | ||
| 3100 | ✗ | fts_doc_id_col = altered_table->s->fields - num_v; | |
| 3101 | ✗ | add_fts_doc_id = true; | |
| 3102 | } | ||
| 3103 | |||
| 3104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
246 | if (!add_fts_doc_idx) { |
| 3105 | fts_doc_id_index_enum ret; | ||
| 3106 | ulint doc_col_no; | ||
| 3107 | |||
| 3108 | ✗ | ret = innobase_fts_check_doc_id_index(nullptr, altered_table, | |
| 3109 | &doc_col_no); | ||
| 3110 | |||
| 3111 | /* This should have been checked before */ | ||
| 3112 | ✗ | ut_ad(ret != FTS_INCORRECT_DOC_ID_INDEX); | |
| 3113 | |||
| 3114 | ✗ | if (ret == FTS_NOT_EXIST_DOC_ID_INDEX) { | |
| 3115 | ✗ | add_fts_doc_idx = true; | |
| 3116 | } else { | ||
| 3117 | ✗ | ut_ad(ret == FTS_EXIST_DOC_ID_INDEX); | |
| 3118 | ✗ | ut_ad(doc_col_no == ULINT_UNDEFINED || doc_col_no == fts_doc_id_col); | |
| 3119 | } | ||
| 3120 | } | ||
| 3121 | } | ||
| 3122 | } else { | ||
| 3123 | /* Create definitions for added secondary indexes. */ | ||
| 3124 | |||
| 3125 |
2/2✓ Branch 0 taken 5506 times.
✓ Branch 1 taken 5293 times.
|
21598 | for (ulint i = 0; i < n_add; i++) { |
| 3126 |
1/2✓ Branch 0 taken 5506 times.
✗ Branch 1 not taken.
|
11012 | innobase_create_index_def(altered_table, new_dd_table, key_info, add[i], |
| 3127 | false, false, indexdef, heap); | ||
| 3128 | |||
| 3129 |
2/2✓ Branch 0 taken 346 times.
✓ Branch 1 taken 5160 times.
|
11012 | if (indexdef->m_ind_type & DICT_FTS) { |
| 3130 | 692 | n_fts_add++; | |
| 3131 | } | ||
| 3132 | |||
| 3133 | 11012 | indexdef++; | |
| 3134 | } | ||
| 3135 | } | ||
| 3136 | |||
| 3137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | assert(index_defs + n_add == indexdef); |
| 3138 | |||
| 3139 |
2/2✓ Branch 0 taken 137 times.
✓ Branch 1 taken 35623 times.
|
71520 | if (add_fts_doc_idx) { |
| 3140 | 274 | ddl::Index_defn *index_def = indexdef++; | |
| 3141 | |||
| 3142 | 274 | index_def->m_fields = static_cast<ddl::Index_field *>( | |
| 3143 |
1/2✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
|
274 | mem_heap_alloc(heap, sizeof *index_def->m_fields)); |
| 3144 | |||
| 3145 | 274 | index_def->m_n_fields = 1; | |
| 3146 | 274 | index_def->m_fields->m_col_no = fts_doc_id_col; | |
| 3147 | 274 | index_def->m_fields->m_prefix_len = 0; | |
| 3148 | 274 | index_def->m_fields->m_is_ascending = true; | |
| 3149 | 274 | index_def->m_fields->m_is_v_col = false; | |
| 3150 | 274 | index_def->m_ind_type = DICT_UNIQUE; | |
| 3151 |
6/8✓ Branch 0 taken 123 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 122 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 122 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 137 times.
|
274 | ut_ad(!rebuild || !add_fts_doc_id || |
| 3152 | fts_doc_id_col <= altered_table->s->fields); | ||
| 3153 | |||
| 3154 | 274 | index_def->m_name = FTS_DOC_ID_INDEX_NAME; | |
| 3155 | 274 | index_def->m_is_ngram = false; | |
| 3156 | 274 | index_def->m_rebuild = rebuild; | |
| 3157 | |||
| 3158 | /* TODO: assign a real MySQL key number for this */ | ||
| 3159 | 274 | index_def->m_key_number = ULINT_UNDEFINED; | |
| 3160 | 274 | n_add++; | |
| 3161 | } | ||
| 3162 | |||
| 3163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | assert(indexdef > index_defs); |
| 3164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | assert((ulint)(indexdef - index_defs) <= |
| 3165 | ha_alter_info->key_count + add_fts_doc_idx + got_default_clust); | ||
| 3166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | assert(ha_alter_info->index_add_count <= n_add); |
| 3167 | 71520 | return index_defs; | |
| 3168 | 71520 | } | |
| 3169 | |||
| 3170 | /** Check each index column size, make sure they do not exceed the max limit | ||
| 3171 | @return true if index column size exceeds limit */ | ||
| 3172 | 7341 | [[nodiscard]] static bool innobase_check_column_length( | |
| 3173 | ulint max_col_len, /*!< in: maximum column length */ | ||
| 3174 | const KEY *key_info) /*!< in: Indexes to be created */ | ||
| 3175 | { | ||
| 3176 |
2/2✓ Branch 0 taken 11145 times.
✓ Branch 1 taken 7337 times.
|
18482 | for (ulint key_part = 0; key_part < key_info->user_defined_key_parts; |
| 3177 | key_part++) { | ||
| 3178 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11141 times.
|
11145 | if (key_info->key_part[key_part].length > max_col_len) { |
| 3179 | 4 | return (true); | |
| 3180 | } | ||
| 3181 | } | ||
| 3182 | 7337 | return (false); | |
| 3183 | } | ||
| 3184 | |||
| 3185 | /** Search for a given column in each index that is not being dropped. Return | ||
| 3186 | true if the column is part of any of the active indexes or it is a system | ||
| 3187 | column. | ||
| 3188 | @param[in] table table object | ||
| 3189 | @param[in] col_no column number of the column which is to be checked | ||
| 3190 | @param[in] is_v if this is a virtual column | ||
| 3191 | @retval true the column exists or it is a system column | ||
| 3192 | @retval false column does not exist */ | ||
| 3193 | 3704 | static bool check_col_exists_in_indexes(const dict_table_t *table, ulint col_no, | |
| 3194 | bool is_v) { | ||
| 3195 | /* This function does not check system columns */ | ||
| 3196 |
6/6✓ Branch 0 taken 3552 times.
✓ Branch 1 taken 152 times.
✓ Branch 2 taken 1194 times.
✓ Branch 3 taken 2358 times.
✓ Branch 4 taken 1194 times.
✓ Branch 5 taken 2510 times.
|
3704 | if (!is_v && table->get_col(col_no)->mtype == DATA_SYS) { |
| 3197 | 1194 | return (true); | |
| 3198 | } | ||
| 3199 | |||
| 3200 |
2/2✓ Branch 0 taken 3884 times.
✓ Branch 1 taken 1959 times.
|
5843 | for (const dict_index_t *index = table->first_index(); index; |
| 3201 | 3333 | index = index->next()) { | |
| 3202 |
2/2✓ Branch 0 taken 2971 times.
✓ Branch 1 taken 3333 times.
|
6304 | for (ulint i = 0; i < index->n_user_defined_cols; i++) { |
| 3203 | 2971 | const dict_col_t *idx_col = index->get_col(i); | |
| 3204 | |||
| 3205 |
6/6✓ Branch 0 taken 230 times.
✓ Branch 1 taken 2741 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 92 times.
✓ Branch 4 taken 138 times.
✓ Branch 5 taken 2833 times.
|
2971 | if (is_v && idx_col->is_virtual()) { |
| 3206 | 138 | const dict_v_col_t *v_col = | |
| 3207 | reinterpret_cast<const dict_v_col_t *>(idx_col); | ||
| 3208 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 113 times.
|
138 | if (v_col->v_pos == col_no) { |
| 3209 | 25 | return (true); | |
| 3210 | } | ||
| 3211 | } | ||
| 3212 | |||
| 3213 |
6/6✓ Branch 0 taken 2741 times.
✓ Branch 1 taken 205 times.
✓ Branch 2 taken 2688 times.
✓ Branch 3 taken 53 times.
✓ Branch 4 taken 526 times.
✓ Branch 5 taken 2420 times.
|
5634 | if (!is_v && !idx_col->is_virtual() && |
| 3214 |
2/2✓ Branch 0 taken 526 times.
✓ Branch 1 taken 2162 times.
|
2688 | dict_col_get_no(idx_col) == col_no) { |
| 3215 | 526 | return (true); | |
| 3216 | } | ||
| 3217 | } | ||
| 3218 | } | ||
| 3219 | |||
| 3220 | 1959 | return (false); | |
| 3221 | } | ||
| 3222 | |||
| 3223 | /** Reset dict_col_t::ord_part for those columns that fail to be indexed, | ||
| 3224 | Check every existing column to see if any current index references them. | ||
| 3225 | This should be checked after an index is dropped during ALTER TABLE. | ||
| 3226 | @param[in,out] table InnoDB table to check */ | ||
| 3227 | 398 | static inline void reset_column_ord_part(dict_table_t *table) { | |
| 3228 |
2/2✓ Branch 0 taken 2383 times.
✓ Branch 1 taken 398 times.
|
2781 | for (ulint i = 0; i < table->get_n_cols(); i++) { |
| 3229 |
2/2✓ Branch 0 taken 915 times.
✓ Branch 1 taken 1468 times.
|
2383 | if (!check_col_exists_in_indexes(table, i, false)) { |
| 3230 | 915 | table->cols[i].ord_part = 0; | |
| 3231 | } | ||
| 3232 | } | ||
| 3233 | |||
| 3234 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 398 times.
|
439 | for (ulint i = 0; i < dict_table_get_n_v_cols(table); i++) { |
| 3235 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 16 times.
|
41 | if (!check_col_exists_in_indexes(table, i, true)) { |
| 3236 | 25 | table->v_cols[i].m_col.ord_part = 0; | |
| 3237 | } | ||
| 3238 | } | ||
| 3239 | 398 | } | |
| 3240 | |||
| 3241 | /** Drop in-memory metadata for index (dict_index_t) left from previous | ||
| 3242 | online ALTER operation. | ||
| 3243 | @param[in] table table to check | ||
| 3244 | @param[in] locked if it is dict_sys mutex locked */ | ||
| 3245 | 47886 | static void online_retry_drop_dict_indexes(dict_table_t *table, bool locked) { | |
| 3246 |
2/2✓ Branch 0 taken 12128 times.
✓ Branch 1 taken 35758 times.
|
47886 | if (!locked) { |
| 3247 | 12128 | dict_sys_mutex_enter(); | |
| 3248 | } | ||
| 3249 | |||
| 3250 | 47886 | bool modify = false; | |
| 3251 | 47886 | dict_index_t *index = table->first_index(); | |
| 3252 | |||
| 3253 |
2/2✓ Branch 0 taken 16927 times.
✓ Branch 1 taken 47886 times.
|
64813 | for (index = index->next(); index != nullptr; index = index->next()) { |
| 3254 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 16922 times.
|
16927 | if (dict_index_get_online_status(index) == ONLINE_INDEX_ABORTED_DROPPED) { |
| 3255 | 5 | dict_index_t *prev = UT_LIST_GET_PREV(indexes, index); | |
| 3256 | |||
| 3257 | 5 | dict_index_remove_from_cache(table, index); | |
| 3258 | |||
| 3259 | 5 | index = prev; | |
| 3260 | |||
| 3261 | 5 | modify = true; | |
| 3262 | } | ||
| 3263 | } | ||
| 3264 | |||
| 3265 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 47881 times.
|
47886 | if (modify) { |
| 3266 | /* Since the table has been modified, table->def_trx_id should be | ||
| 3267 | adjusted like ddl::drop_indexes(). However, this function may | ||
| 3268 | be called before the DDL transaction starts, so it is impossible to | ||
| 3269 | get current DDL transaction ID. Thus advancing def_trx_id by 1 to | ||
| 3270 | simply inform other threads about this change. */ | ||
| 3271 | 5 | ++table->def_trx_id; | |
| 3272 | |||
| 3273 | 5 | reset_column_ord_part(table); | |
| 3274 | } | ||
| 3275 | |||
| 3276 |
2/2✓ Branch 0 taken 12128 times.
✓ Branch 1 taken 35758 times.
|
47886 | if (!locked) { |
| 3277 | 12128 | dict_sys_mutex_exit(); | |
| 3278 | } | ||
| 3279 | 47886 | } | |
| 3280 | |||
| 3281 | /** Determines if InnoDB is dropping a foreign key constraint. | ||
| 3282 | @param foreign the constraint | ||
| 3283 | @param drop_fk constraints being dropped | ||
| 3284 | @param n_drop_fk number of constraints that are being dropped | ||
| 3285 | @return whether the constraint is being dropped */ | ||
| 3286 | 14 | [[nodiscard]] inline bool innobase_dropping_foreign( | |
| 3287 | const dict_foreign_t *foreign, dict_foreign_t **drop_fk, ulint n_drop_fk) { | ||
| 3288 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
|
14 | while (n_drop_fk--) { |
| 3289 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (*drop_fk++ == foreign) { |
| 3290 | 2 | return (true); | |
| 3291 | } | ||
| 3292 | } | ||
| 3293 | |||
| 3294 | 12 | return (false); | |
| 3295 | } | ||
| 3296 | |||
| 3297 | /** Convert a default value for ADD COLUMN. | ||
| 3298 | |||
| 3299 | @param heap Memory heap where allocated | ||
| 3300 | @param dfield InnoDB data field to copy to | ||
| 3301 | @param field MySQL value for the column | ||
| 3302 | @param comp nonzero if in compact format */ | ||
| 3303 | 17730 | static void innobase_build_col_map_add(mem_heap_t *heap, dfield_t *dfield, | |
| 3304 | const Field *field, ulint comp, | ||
| 3305 | row_prebuilt_t *prebuilt) { | ||
| 3306 |
2/2✓ Branch 0 taken 13625 times.
✓ Branch 1 taken 4105 times.
|
17730 | if (field->is_real_null()) { |
| 3307 | 13625 | dfield_set_null(dfield); | |
| 3308 | 13625 | return; | |
| 3309 | } | ||
| 3310 | |||
| 3311 | 4105 | ulint size = field->pack_length(); | |
| 3312 | |||
| 3313 | 4105 | byte *buf = static_cast<byte *>(mem_heap_alloc(heap, size)); | |
| 3314 | |||
| 3315 | 4105 | const byte *mysql_data = field->field_ptr(); | |
| 3316 | |||
| 3317 | 4105 | row_mysql_store_col_in_innobase_format( | |
| 3318 | dfield, buf, true, mysql_data, size, comp, | ||
| 3319 | 4105 | field->column_format() == COLUMN_FORMAT_TYPE_COMPRESSED, | |
| 3320 | 4105 | reinterpret_cast<const byte *>(field->zip_dict_data.str), | |
| 3321 | 4105 | field->zip_dict_data.length, &prebuilt->compress_heap); | |
| 3322 | } | ||
| 3323 | |||
| 3324 | /** Construct the translation table for reordering, dropping or | ||
| 3325 | adding columns. | ||
| 3326 | |||
| 3327 | @param ha_alter_info Data used during in-place alter | ||
| 3328 | @param altered_table MySQL table that is being altered | ||
| 3329 | @param table MySQL table as it is before the ALTER operation | ||
| 3330 | @param new_table InnoDB table corresponding to MySQL altered_table | ||
| 3331 | @param old_table InnoDB table corresponding to MYSQL table | ||
| 3332 | @param add_cols Default values for ADD COLUMN, or NULL if no ADD COLUMN | ||
| 3333 | @param heap Memory heap where allocated | ||
| 3334 | @return array of integers, mapping column numbers in the table | ||
| 3335 | to column numbers in altered_table */ | ||
| 3336 | 30438 | [[nodiscard]] static const ulint *innobase_build_col_map( | |
| 3337 | Alter_inplace_info *ha_alter_info, const TABLE *altered_table, | ||
| 3338 | const TABLE *table, const dict_table_t *new_table, | ||
| 3339 | const dict_table_t *old_table, dtuple_t *add_cols, mem_heap_t *heap, | ||
| 3340 | row_prebuilt_t *prebuilt) { | ||
| 3341 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
30438 | DBUG_TRACE; |
| 3342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
30438 | assert(altered_table != table); |
| 3343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
30438 | assert(new_table != old_table); |
| 3344 |
3/6✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30438 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30438 times.
|
30438 | assert(new_table->get_n_cols() + dict_table_get_n_v_cols(new_table) >= |
| 3345 | altered_table->s->fields + DATA_N_SYS_COLS); | ||
| 3346 |
3/6✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30438 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30438 times.
|
30438 | assert(old_table->get_n_cols() + dict_table_get_n_v_cols(old_table) >= |
| 3347 | table->s->fields + DATA_N_SYS_COLS); | ||
| 3348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
30438 | assert(!!add_cols == |
| 3349 | !!(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN)); | ||
| 3350 |
5/8✓ Branch 0 taken 9342 times.
✓ Branch 1 taken 21096 times.
✓ Branch 2 taken 9342 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9342 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9342 times.
|
30438 | assert(!add_cols || dtuple_get_n_fields(add_cols) == new_table->get_n_cols()); |
| 3351 | |||
| 3352 | 60876 | ulint *col_map = static_cast<ulint *>(mem_heap_alloc( | |
| 3353 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
30438 | heap, (old_table->n_cols + old_table->n_v_cols) * sizeof *col_map)); |
| 3354 | |||
| 3355 | List_iterator_fast<Create_field> cf_it( | ||
| 3356 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
30438 | ha_alter_info->alter_info->create_list); |
| 3357 | 30438 | uint i = 0; | |
| 3358 | 30438 | uint num_v = 0; | |
| 3359 | |||
| 3360 | /* Any dropped columns will map to ULINT_UNDEFINED. */ | ||
| 3361 |
2/2✓ Branch 0 taken 208901 times.
✓ Branch 1 taken 30438 times.
|
239339 | for (uint old_i = 0; old_i + DATA_N_SYS_COLS < old_table->n_cols; old_i++) { |
| 3362 | 208901 | col_map[old_i] = ULINT_UNDEFINED; | |
| 3363 | } | ||
| 3364 | |||
| 3365 |
2/2✓ Branch 0 taken 837 times.
✓ Branch 1 taken 30438 times.
|
31275 | for (uint old_i = 0; old_i < old_table->n_v_cols; old_i++) { |
| 3366 | 837 | col_map[old_i + old_table->n_cols] = ULINT_UNDEFINED; | |
| 3367 | } | ||
| 3368 | |||
| 3369 |
2/2✓ Branch 0 taken 225961 times.
✓ Branch 1 taken 30438 times.
|
256399 | while (const Create_field *new_field = cf_it++) { |
| 3370 | 225961 | bool is_v = false; | |
| 3371 | |||
| 3372 |
4/4✓ Branch 0 taken 859 times.
✓ Branch 1 taken 225102 times.
✓ Branch 2 taken 837 times.
✓ Branch 3 taken 22 times.
|
225961 | if (innobase_is_v_fld(new_field)) { |
| 3373 | 837 | is_v = true; | |
| 3374 | } | ||
| 3375 | |||
| 3376 | 225961 | ulint num_old_v = 0; | |
| 3377 | |||
| 3378 |
2/2✓ Branch 0 taken 3048065 times.
✓ Branch 1 taken 17730 times.
|
3065795 | for (uint old_i = 0; table->field[old_i]; old_i++) { |
| 3379 | 3048065 | const Field *field = table->field[old_i]; | |
| 3380 |
4/4✓ Branch 0 taken 950 times.
✓ Branch 1 taken 3047115 times.
✓ Branch 2 taken 890 times.
✓ Branch 3 taken 60 times.
|
3048065 | if (innobase_is_v_fld(field)) { |
| 3381 |
4/4✓ Branch 0 taken 856 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 837 times.
✓ Branch 3 taken 19 times.
|
890 | if (is_v && new_field->field == field) { |
| 3382 | 837 | col_map[old_table->n_cols + num_v] = num_old_v; | |
| 3383 | 837 | num_old_v++; | |
| 3384 | 837 | goto found_col; | |
| 3385 | } | ||
| 3386 | 53 | num_old_v++; | |
| 3387 | 53 | continue; | |
| 3388 | } | ||
| 3389 | |||
| 3390 |
2/2✓ Branch 0 taken 207394 times.
✓ Branch 1 taken 2839781 times.
|
3047175 | if (new_field->field == field) { |
| 3391 | 207394 | col_map[old_i - num_old_v] = i; | |
| 3392 | 207394 | goto found_col; | |
| 3393 | } | ||
| 3394 | } | ||
| 3395 | |||
| 3396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17730 times.
|
17730 | ut_ad(!is_v); |
| 3397 |
1/2✓ Branch 0 taken 17730 times.
✗ Branch 1 not taken.
|
17730 | innobase_build_col_map_add(heap, dtuple_get_nth_field(add_cols, i), |
| 3398 | 17730 | altered_table->field[i + num_v], | |
| 3399 |
2/4✓ Branch 0 taken 17730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17730 times.
✗ Branch 3 not taken.
|
17730 | dict_table_is_comp(new_table), prebuilt); |
| 3400 | 225961 | found_col: | |
| 3401 |
2/2✓ Branch 0 taken 837 times.
✓ Branch 1 taken 225124 times.
|
225961 | if (is_v) { |
| 3402 | 837 | num_v++; | |
| 3403 | } else { | ||
| 3404 | 225124 | i++; | |
| 3405 | } | ||
| 3406 | 225961 | } | |
| 3407 | |||
| 3408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
30438 | assert(i == altered_table->s->fields - num_v); |
| 3409 | |||
| 3410 | 30438 | i = table->s->fields - old_table->n_v_cols; | |
| 3411 | |||
| 3412 | /* Add the InnoDB hidden FTS_DOC_ID column, if any. */ | ||
| 3413 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 30403 times.
|
30438 | if (i + DATA_N_SYS_COLS < old_table->n_cols) { |
| 3414 | /* There should be exactly one extra field, | ||
| 3415 | the FTS_DOC_ID. */ | ||
| 3416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | assert(DICT_TF2_FLAG_IS_SET(old_table, DICT_TF2_FTS_HAS_DOC_ID)); |
| 3417 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | assert(i + DATA_N_SYS_COLS + 1 == old_table->n_cols); |
| 3418 |
2/4✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
|
35 | assert(!strcmp(old_table->get_col_name(i), FTS_DOC_ID_COL_NAME)); |
| 3419 | 35 | if (altered_table->s->fields + DATA_N_SYS_COLS - new_table->n_v_cols < | |
| 3420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | new_table->n_cols) { |
| 3421 | ✗ | assert(DICT_TF2_FLAG_IS_SET(new_table, DICT_TF2_FTS_HAS_DOC_ID)); | |
| 3422 | ✗ | assert(altered_table->s->fields + DATA_N_SYS_COLS + 1 == | |
| 3423 | static_cast<ulint>(new_table->n_cols + new_table->n_v_cols)); | ||
| 3424 | ✗ | col_map[i] = altered_table->s->fields - new_table->n_v_cols; | |
| 3425 | } else { | ||
| 3426 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | assert(!DICT_TF2_FLAG_IS_SET(new_table, DICT_TF2_FTS_HAS_DOC_ID)); |
| 3427 | 35 | col_map[i] = ULINT_UNDEFINED; | |
| 3428 | } | ||
| 3429 | |||
| 3430 | 35 | i++; | |
| 3431 | } else { | ||
| 3432 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30403 times.
|
30403 | assert(!DICT_TF2_FLAG_IS_SET(old_table, DICT_TF2_FTS_HAS_DOC_ID)); |
| 3433 | } | ||
| 3434 | |||
| 3435 |
2/2✓ Branch 0 taken 91314 times.
✓ Branch 1 taken 30438 times.
|
121752 | for (; i < old_table->n_cols; i++) { |
| 3436 | 91314 | col_map[i] = i + new_table->n_cols - old_table->n_cols; | |
| 3437 | } | ||
| 3438 | |||
| 3439 | 30438 | return col_map; | |
| 3440 | 30438 | } | |
| 3441 | |||
| 3442 | /** Drop newly create FTS index related auxiliary table during | ||
| 3443 | FIC create index process, before fts_add_index is called | ||
| 3444 | @param table table that was being rebuilt online | ||
| 3445 | @param trx transaction | ||
| 3446 | @return DB_SUCCESS if successful, otherwise last error code | ||
| 3447 | */ | ||
| 3448 | 4 | static dberr_t innobase_drop_fts_index_table(dict_table_t *table, trx_t *trx) { | |
| 3449 | 4 | dberr_t ret_err = DB_SUCCESS; | |
| 3450 | |||
| 3451 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
|
16 | for (dict_index_t *index = table->first_index(); index != nullptr; |
| 3452 | 12 | index = index->next()) { | |
| 3453 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | if (index->type & DICT_FTS) { |
| 3454 | dberr_t err; | ||
| 3455 | |||
| 3456 | 4 | err = fts_drop_index_tables(trx, index, nullptr); | |
| 3457 | |||
| 3458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (err != DB_SUCCESS) { |
| 3459 | ✗ | ret_err = err; | |
| 3460 | } | ||
| 3461 | } | ||
| 3462 | } | ||
| 3463 | |||
| 3464 | 4 | return (ret_err); | |
| 3465 | } | ||
| 3466 | |||
| 3467 | /** Get the new non-virtual column names if any columns were renamed | ||
| 3468 | @param ha_alter_info Data used during in-place alter | ||
| 3469 | @param altered_table MySQL table that is being altered | ||
| 3470 | @param table MySQL table as it is before the ALTER operation | ||
| 3471 | @param user_table InnoDB table as it is before the ALTER operation | ||
| 3472 | @param heap Memory heap for the allocation | ||
| 3473 | @return array of new column names in rebuilt_table, or NULL if not renamed */ | ||
| 3474 | 64 | [[nodiscard]] static const char **innobase_get_col_names( | |
| 3475 | Alter_inplace_info *ha_alter_info, const TABLE *altered_table, | ||
| 3476 | const TABLE *table, const dict_table_t *user_table, mem_heap_t *heap) { | ||
| 3477 | const char **cols; | ||
| 3478 | uint i; | ||
| 3479 | |||
| 3480 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | DBUG_TRACE; |
| 3481 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | assert(user_table->n_t_def > table->s->fields); |
| 3482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | assert(ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME); |
| 3483 | |||
| 3484 | cols = static_cast<const char **>( | ||
| 3485 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | mem_heap_zalloc(heap, user_table->n_def * sizeof *cols)); |
| 3486 | |||
| 3487 | 64 | i = 0; | |
| 3488 | List_iterator_fast<Create_field> cf_it( | ||
| 3489 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | ha_alter_info->alter_info->create_list); |
| 3490 |
2/2✓ Branch 0 taken 272 times.
✓ Branch 1 taken 64 times.
|
336 | while (const Create_field *new_field = cf_it++) { |
| 3491 | 272 | ulint num_v = 0; | |
| 3492 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 272 times.
|
272 | assert(i < altered_table->s->fields); |
| 3493 | |||
| 3494 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
272 | if (innobase_is_v_fld(new_field)) { |
| 3495 | 44 | continue; | |
| 3496 | } | ||
| 3497 | |||
| 3498 |
2/2✓ Branch 0 taken 706 times.
✓ Branch 1 taken 7 times.
|
713 | for (uint old_i = 0; table->field[old_i]; old_i++) { |
| 3499 |
3/4✓ Branch 0 taken 34 times.
✓ Branch 1 taken 672 times.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
706 | if (innobase_is_v_fld(table->field[old_i])) { |
| 3500 | 34 | num_v++; | |
| 3501 | } | ||
| 3502 | |||
| 3503 |
2/2✓ Branch 0 taken 221 times.
✓ Branch 1 taken 485 times.
|
706 | if (new_field->field == table->field[old_i]) { |
| 3504 | 221 | cols[old_i - num_v] = new_field->field_name; | |
| 3505 | 221 | break; | |
| 3506 | } | ||
| 3507 | } | ||
| 3508 | |||
| 3509 | 228 | i++; | |
| 3510 | 272 | } | |
| 3511 | |||
| 3512 | /* Copy the internal column names. */ | ||
| 3513 | 64 | i = table->s->fields - user_table->n_v_def; | |
| 3514 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | cols[i] = user_table->get_col_name(i); |
| 3515 | |||
| 3516 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 64 times.
|
196 | while (++i < user_table->n_def) { |
| 3517 | 132 | cols[i] = cols[i - 1] + strlen(cols[i - 1]) + 1; | |
| 3518 | } | ||
| 3519 | |||
| 3520 | 64 | return cols; | |
| 3521 | 64 | } | |
| 3522 | |||
| 3523 | /** Check whether the column prefix is increased, decreased, or unchanged. | ||
| 3524 | @param[in] new_prefix_len new prefix length | ||
| 3525 | @param[in] old_prefix_len new prefix length | ||
| 3526 | @retval 1 prefix is increased | ||
| 3527 | @retval 0 prefix is unchanged | ||
| 3528 | @retval -1 prefix is decreased */ | ||
| 3529 | 39865 | static inline lint innobase_pk_col_prefix_compare(ulint new_prefix_len, | |
| 3530 | ulint old_prefix_len) { | ||
| 3531 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39865 times.
|
39865 | ut_ad(new_prefix_len < REC_MAX_DATA_SIZE); |
| 3532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39865 times.
|
39865 | ut_ad(old_prefix_len < REC_MAX_DATA_SIZE); |
| 3533 | |||
| 3534 |
2/2✓ Branch 0 taken 39798 times.
✓ Branch 1 taken 67 times.
|
39865 | if (new_prefix_len == old_prefix_len) { |
| 3535 | 39798 | return (0); | |
| 3536 | } | ||
| 3537 | |||
| 3538 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 52 times.
|
67 | if (new_prefix_len == 0) { |
| 3539 | 15 | new_prefix_len = ULINT_MAX; | |
| 3540 | } | ||
| 3541 | |||
| 3542 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 51 times.
|
67 | if (old_prefix_len == 0) { |
| 3543 | 16 | old_prefix_len = ULINT_MAX; | |
| 3544 | } | ||
| 3545 | |||
| 3546 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 36 times.
|
67 | if (new_prefix_len > old_prefix_len) { |
| 3547 | 31 | return (1); | |
| 3548 | } else { | ||
| 3549 | 36 | return (-1); | |
| 3550 | } | ||
| 3551 | } | ||
| 3552 | |||
| 3553 | /** Check whether the column is existing in old table. | ||
| 3554 | @param[in] new_col_no new column no | ||
| 3555 | @param[in] col_map mapping of old column numbers to new ones | ||
| 3556 | @param[in] col_map_size the column map size | ||
| 3557 | @return true if the column is existing, otherwise false. */ | ||
| 3558 | 120 | static inline bool innobase_pk_col_is_existing(const ulint new_col_no, | |
| 3559 | const ulint *col_map, | ||
| 3560 | const ulint col_map_size) { | ||
| 3561 |
2/2✓ Branch 0 taken 549 times.
✓ Branch 1 taken 64 times.
|
613 | for (ulint i = 0; i < col_map_size; i++) { |
| 3562 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 493 times.
|
549 | if (col_map[i] == new_col_no) { |
| 3563 | 56 | return (true); | |
| 3564 | } | ||
| 3565 | } | ||
| 3566 | |||
| 3567 | 64 | return (false); | |
| 3568 | } | ||
| 3569 | |||
| 3570 | /** Determine whether both the indexes have same set of primary key | ||
| 3571 | fields arranged in the same order. | ||
| 3572 | |||
| 3573 | Rules when we cannot skip sorting: | ||
| 3574 | (1) Removing existing PK columns somewhere else than at the end of the PK; | ||
| 3575 | (2) Adding existing columns to the PK, except at the end of the PK when no | ||
| 3576 | columns are removed from the PK; | ||
| 3577 | (3) Changing the order of existing PK columns; | ||
| 3578 | (4) Decreasing the prefix length just like removing existing PK columns | ||
| 3579 | follows rule(1), Increasing the prefix length just like adding existing | ||
| 3580 | PK columns follows rule(2); | ||
| 3581 | (5) Changing the ascending order of the existing PK columns. | ||
| 3582 | @param[in] col_map mapping of old column numbers to new ones | ||
| 3583 | @param[in] old_clust_index index to be compared | ||
| 3584 | @param[in] new_clust_index index to be compared | ||
| 3585 | @retval true if both indexes have same order. | ||
| 3586 | @retval false. */ | ||
| 3587 | 30364 | [[nodiscard]] static bool innobase_pk_order_preserved( | |
| 3588 | const ulint *col_map, const dict_index_t *old_clust_index, | ||
| 3589 | const dict_index_t *new_clust_index) { | ||
| 3590 | 30364 | ulint old_n_uniq = dict_index_get_n_ordering_defined_by_user(old_clust_index); | |
| 3591 | 30364 | ulint new_n_uniq = dict_index_get_n_ordering_defined_by_user(new_clust_index); | |
| 3592 | |||
| 3593 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30364 times.
|
30364 | ut_ad(old_clust_index->is_clustered()); |
| 3594 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30364 times.
|
30364 | ut_ad(new_clust_index->is_clustered()); |
| 3595 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30364 times.
|
30364 | ut_ad(old_clust_index->table != new_clust_index->table); |
| 3596 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30364 times.
|
30364 | ut_ad(col_map != nullptr); |
| 3597 | |||
| 3598 |
2/2✓ Branch 0 taken 7683 times.
✓ Branch 1 taken 22681 times.
|
30364 | if (old_n_uniq == 0) { |
| 3599 | /* There was no PRIMARY KEY in the table. | ||
| 3600 | If there is no PRIMARY KEY after the ALTER either, | ||
| 3601 | no sorting is needed. */ | ||
| 3602 | 7683 | return (new_n_uniq == old_n_uniq); | |
| 3603 | } | ||
| 3604 | |||
| 3605 | /* DROP PRIMARY KEY is only allowed in combination with | ||
| 3606 | ADD PRIMARY KEY. */ | ||
| 3607 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22681 times.
|
22681 | ut_ad(new_n_uniq > 0); |
| 3608 | |||
| 3609 | /* The order of the last processed new_clust_index key field, | ||
| 3610 | not counting ADD COLUMN, which are constant. */ | ||
| 3611 | 22681 | lint last_field_order = -1; | |
| 3612 | 22681 | ulint existing_field_count = 0; | |
| 3613 | 22681 | ulint old_n_cols = old_clust_index->table->get_n_cols(); | |
| 3614 |
2/2✓ Branch 0 taken 40504 times.
✓ Branch 1 taken 22123 times.
|
62627 | for (ulint new_field = 0; new_field < new_n_uniq; new_field++) { |
| 3615 | 40504 | ulint new_col_no = new_clust_index->fields[new_field].col->ind; | |
| 3616 | |||
| 3617 | /* Check if there is a match in old primary key. */ | ||
| 3618 | 40504 | ulint old_field = 0; | |
| 3619 |
2/2✓ Branch 0 taken 72141 times.
✓ Branch 1 taken 120 times.
|
72261 | while (old_field < old_n_uniq) { |
| 3620 | 72141 | ulint old_col_no = old_clust_index->fields[old_field].col->ind; | |
| 3621 | |||
| 3622 |
2/2✓ Branch 0 taken 40384 times.
✓ Branch 1 taken 31757 times.
|
72141 | if (col_map[old_col_no] == new_col_no) { |
| 3623 | 40384 | break; | |
| 3624 | } | ||
| 3625 | |||
| 3626 | 31757 | old_field++; | |
| 3627 | } | ||
| 3628 | |||
| 3629 | /* The order of key field in the new primary key. | ||
| 3630 | 1. old PK column: idx in old primary key | ||
| 3631 | 2. existing column: old_n_uniq + sequence no | ||
| 3632 | 3. newly added column: no order */ | ||
| 3633 | lint new_field_order; | ||
| 3634 | 40504 | const bool old_pk_column = old_field < old_n_uniq; | |
| 3635 | |||
| 3636 |
2/2✓ Branch 0 taken 40384 times.
✓ Branch 1 taken 120 times.
|
40504 | if (old_pk_column) { |
| 3637 | 40384 | new_field_order = old_field; | |
| 3638 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 64 times.
|
120 | } else if (innobase_pk_col_is_existing(new_col_no, col_map, old_n_cols)) { |
| 3639 | 56 | new_field_order = old_n_uniq + existing_field_count++; | |
| 3640 | } else { | ||
| 3641 | /* Skip newly added column. */ | ||
| 3642 | 64 | continue; | |
| 3643 | } | ||
| 3644 | |||
| 3645 |
2/2✓ Branch 0 taken 549 times.
✓ Branch 1 taken 39891 times.
|
40440 | if (last_field_order + 1 != new_field_order) { |
| 3646 | /* Old PK order is not kept, or existing column | ||
| 3647 | is not added at the end of old PK. */ | ||
| 3648 | 549 | return (false); | |
| 3649 | } | ||
| 3650 | |||
| 3651 | 39891 | last_field_order = new_field_order; | |
| 3652 | |||
| 3653 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 39865 times.
|
39891 | if (!old_pk_column) { |
| 3654 | 26 | continue; | |
| 3655 | } | ||
| 3656 | |||
| 3657 | /* Check prefix length change. */ | ||
| 3658 | 79730 | const lint prefix_change = innobase_pk_col_prefix_compare( | |
| 3659 | 39865 | new_clust_index->fields[new_field].prefix_len, | |
| 3660 | 39865 | old_clust_index->fields[old_field].prefix_len); | |
| 3661 | |||
| 3662 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 39829 times.
|
39865 | if (prefix_change < 0) { |
| 3663 | /* If a column's prefix length is decreased, it should | ||
| 3664 | be the last old PK column in new PK. | ||
| 3665 | Note: we set last_field_order to -2, so that if there | ||
| 3666 | are any old PK colmns or existing columns after it in | ||
| 3667 | new PK, the comparison to new_field_order will fail in | ||
| 3668 | the next round.*/ | ||
| 3669 | 36 | last_field_order = -2; | |
| 3670 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 39798 times.
|
39829 | } else if (prefix_change > 0) { |
| 3671 | /* If a column's prefix length is increased, it should | ||
| 3672 | be the last PK column in old PK. */ | ||
| 3673 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 24 times.
|
31 | if (old_field != old_n_uniq - 1) { |
| 3674 | 7 | return (false); | |
| 3675 | } | ||
| 3676 | } | ||
| 3677 | |||
| 3678 | /* Check new primary key field ascending or descending changes | ||
| 3679 | compared to old primary key field. */ | ||
| 3680 | 39858 | bool change_asc = (new_clust_index->fields[new_field].is_ascending == | |
| 3681 | 39858 | old_clust_index->fields[old_field].is_ascending); | |
| 3682 | |||
| 3683 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 39856 times.
|
39858 | if (!change_asc) { |
| 3684 | 2 | return (false); | |
| 3685 | } | ||
| 3686 | } | ||
| 3687 | |||
| 3688 | 22123 | return (true); | |
| 3689 | } | ||
| 3690 | |||
| 3691 | /** Check if we are creating spatial indexes on GIS columns, which are | ||
| 3692 | legacy columns from earlier MySQL, such as 5.6. If so, we have to update | ||
| 3693 | the mtypes of the old GIS columns to DATA_GEOMETRY. | ||
| 3694 | In 5.6, we store GIS columns as DATA_BLOB in InnoDB layer, it will introduce | ||
| 3695 | confusion when we run latest server on older data. That's why we need to | ||
| 3696 | do the upgrade. | ||
| 3697 | @param[in] ha_alter_info Data used during in-place alter | ||
| 3698 | @param[in] table Table on which we want to add indexes | ||
| 3699 | @return DB_SUCCESS if update successfully or no columns need to be updated, | ||
| 3700 | otherwise DB_ERROR, which means we can't update the mtype for some | ||
| 3701 | column, and creating spatial index on it should be dangerous */ | ||
| 3702 | 5286 | static dberr_t innobase_check_gis_columns(Alter_inplace_info *ha_alter_info, | |
| 3703 | dict_table_t *table) { | ||
| 3704 |
1/2✓ Branch 0 taken 5286 times.
✗ Branch 1 not taken.
|
5286 | DBUG_TRACE; |
| 3705 | |||
| 3706 |
2/2✓ Branch 0 taken 5497 times.
✓ Branch 1 taken 5286 times.
|
10783 | for (uint key_num = 0; key_num < ha_alter_info->index_add_count; key_num++) { |
| 3707 | 5497 | const KEY &key = | |
| 3708 | ha_alter_info | ||
| 3709 | 5497 | ->key_info_buffer[ha_alter_info->index_add_buffer[key_num]]; | |
| 3710 | |||
| 3711 |
2/2✓ Branch 0 taken 5420 times.
✓ Branch 1 taken 77 times.
|
5497 | if (!(key.flags & HA_SPATIAL)) { |
| 3712 | 5497 | continue; | |
| 3713 | } | ||
| 3714 | |||
| 3715 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
|
77 | ut_ad(key.user_defined_key_parts == 1); |
| 3716 | 77 | const KEY_PART_INFO &key_part = key.key_part[0]; | |
| 3717 | |||
| 3718 | /* Does not support spatial index on virtual columns */ | ||
| 3719 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
77 | if (innobase_is_v_fld(key_part.field)) { |
| 3720 | ✗ | return DB_UNSUPPORTED; | |
| 3721 | } | ||
| 3722 | |||
| 3723 | 154 | ulint col_nr = dict_table_has_column(table, key_part.field->field_name, | |
| 3724 |
1/2✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
|
77 | key_part.fieldnr); |
| 3725 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
|
77 | ut_ad(col_nr != table->n_def); |
| 3726 | 77 | dict_col_t *col = &table->cols[col_nr]; | |
| 3727 | |||
| 3728 |
1/2✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
|
77 | if (col->mtype != DATA_BLOB) { |
| 3729 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
|
77 | ut_ad(DATA_GEOMETRY_MTYPE(col->mtype)); |
| 3730 | 77 | continue; | |
| 3731 | } | ||
| 3732 | |||
| 3733 | ✗ | const char *col_name = table->get_col_name(col_nr); | |
| 3734 | ✗ | col->mtype = DATA_GEOMETRY; | |
| 3735 | |||
| 3736 | ✗ | ib::info(ER_IB_MSG_598) | |
| 3737 | ✗ | << "Updated mtype of column" << col_name << " in table " << table->name | |
| 3738 | ✗ | << ", whose id is " << table->id << " to DATA_GEOMETRY"; | |
| 3739 | } | ||
| 3740 | |||
| 3741 | 5286 | return DB_SUCCESS; | |
| 3742 | 5286 | } | |
| 3743 | |||
| 3744 | /** Update the attributes for the implicit tablespaces | ||
| 3745 | @param[in] thd THD object | ||
| 3746 | @param[in] ha_alter_info Data used during in-place alter | ||
| 3747 | @param[in] table MySQL table that is being modified | ||
| 3748 | @return true Failure | ||
| 3749 | @return false Success */ | ||
| 3750 | 5034 | static bool prepare_inplace_change_implicit_tablespace_option( | |
| 3751 | THD *thd, Alter_inplace_info *ha_alter_info, const dict_table_t *table) { | ||
| 3752 |
1/2✓ Branch 0 taken 5034 times.
✗ Branch 1 not taken.
|
5034 | dd::cache::Dictionary_client *client = dd::get_dd_client(thd); |
| 3753 |
1/2✓ Branch 0 taken 5034 times.
✗ Branch 1 not taken.
|
5034 | dd::cache::Dictionary_client::Auto_releaser releaser(client); |
| 3754 | |||
| 3755 | 5034 | dd::Object_id space_id = table->dd_space_id; | |
| 3756 | |||
| 3757 |
1/2✓ Branch 0 taken 5034 times.
✗ Branch 1 not taken.
|
5034 | return dd_implicit_alter_tablespace(client, space_id, |
| 3758 | 10068 | ha_alter_info->create_info); | |
| 3759 | 5034 | } | |
| 3760 | |||
| 3761 | /** Collect virtual column info for its addition | ||
| 3762 | @param[in] ha_alter_info Data used during in-place alter | ||
| 3763 | @param[in] altered_table MySQL table that is being altered to | ||
| 3764 | @param[in] table MySQL table as it is before the ALTER operation | ||
| 3765 | @retval true Failure | ||
| 3766 | @retval false Success */ | ||
| 3767 | 317 | static bool prepare_inplace_add_virtual(Alter_inplace_info *ha_alter_info, | |
| 3768 | const TABLE *altered_table, | ||
| 3769 | const TABLE *table) { | ||
| 3770 | ha_innobase_inplace_ctx *ctx; | ||
| 3771 | 317 | ulint i = 0; | |
| 3772 | 317 | ulint j = 0; | |
| 3773 | const Create_field *new_field; | ||
| 3774 | |||
| 3775 | 317 | ctx = static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | |
| 3776 | |||
| 3777 | 634 | ctx->add_vcol = static_cast<dict_v_col_t *>(mem_heap_zalloc( | |
| 3778 | ctx->heap, | ||
| 3779 |
1/2✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
|
317 | ha_alter_info->virtual_column_add_count * sizeof *ctx->add_vcol)); |
| 3780 | 634 | ctx->add_vcol_name = static_cast<const char **>(mem_heap_alloc( | |
| 3781 | ctx->heap, | ||
| 3782 |
1/2✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
|
317 | ha_alter_info->virtual_column_add_count * sizeof *ctx->add_vcol_name)); |
| 3783 | |||
| 3784 | List_iterator_fast<Create_field> cf_it( | ||
| 3785 |
1/2✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
|
317 | ha_alter_info->alter_info->create_list); |
| 3786 | |||
| 3787 |
2/2✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 316 times.
|
1894 | while ((new_field = (cf_it++)) != nullptr) { |
| 3788 | 1578 | const Field *field = new_field->field; | |
| 3789 | ulint old_i; | ||
| 3790 | |||
| 3791 |
2/2✓ Branch 0 taken 4828 times.
✓ Branch 1 taken 330 times.
|
5158 | for (old_i = 0; table->field[old_i]; old_i++) { |
| 3792 | 4828 | const Field *n_field = table->field[old_i]; | |
| 3793 |
2/2✓ Branch 0 taken 1248 times.
✓ Branch 1 taken 3580 times.
|
4828 | if (field == n_field) { |
| 3794 | 1248 | break; | |
| 3795 | } | ||
| 3796 | } | ||
| 3797 | |||
| 3798 | 1578 | i++; | |
| 3799 | |||
| 3800 |
2/2✓ Branch 0 taken 1248 times.
✓ Branch 1 taken 330 times.
|
1578 | if (table->field[old_i]) { |
| 3801 | 1248 | continue; | |
| 3802 | } | ||
| 3803 | |||
| 3804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
|
330 | ut_ad(!field); |
| 3805 | |||
| 3806 | ulint col_len; | ||
| 3807 | ulint is_unsigned; | ||
| 3808 | ulint field_type; | ||
| 3809 | ulint charset_no; | ||
| 3810 | |||
| 3811 | 330 | field = altered_table->field[i - 1]; | |
| 3812 | |||
| 3813 |
1/2✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
|
330 | ulint col_type = get_innobase_type_from_mysql_type(&is_unsigned, field); |
| 3814 |
1/2✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
|
330 | bool is_multi_value = innobase_is_multi_value_fld(field); |
| 3815 | |||
| 3816 |
2/4✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 330 times.
|
330 | if (!field->gcol_info || field->stored_in_db) { |
| 3817 | ✗ | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); | |
| 3818 | 1 | return (true); | |
| 3819 | } | ||
| 3820 | |||
| 3821 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 234 times.
|
330 | if (is_multi_value) { |
| 3822 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | col_len = field->key_length(); |
| 3823 | } else { | ||
| 3824 |
1/2✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
|
234 | col_len = field->pack_length(); |
| 3825 | } | ||
| 3826 |
1/2✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
|
330 | field_type = (ulint)field->type(); |
| 3827 | |||
| 3828 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 329 times.
|
330 | if (!field->is_nullable()) { |
| 3829 | 1 | field_type |= DATA_NOT_NULL; | |
| 3830 | } | ||
| 3831 | |||
| 3832 |
3/4✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 304 times.
✓ Branch 3 taken 26 times.
|
330 | if (field->binary()) { |
| 3833 | 304 | field_type |= DATA_BINARY_TYPE; | |
| 3834 | } | ||
| 3835 | |||
| 3836 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 304 times.
|
330 | if (is_unsigned) { |
| 3837 | 26 | field_type |= DATA_UNSIGNED; | |
| 3838 | } | ||
| 3839 | |||
| 3840 |
3/4✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 260 times.
|
330 | if (dtype_is_string_type(col_type)) { |
| 3841 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | charset_no = (ulint)field->charset()->number; |
| 3842 | |||
| 3843 |
3/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 69 times.
|
70 | DBUG_EXECUTE_IF("ib_alter_add_virtual_fail", |
| 3844 | charset_no += MAX_CHAR_COLL_NUM;); | ||
| 3845 | |||
| 3846 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 69 times.
|
70 | if (charset_no > MAX_CHAR_COLL_NUM) { |
| 3847 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); |
| 3848 | 1 | return (true); | |
| 3849 | } | ||
| 3850 | } else { | ||
| 3851 | 260 | charset_no = 0; | |
| 3852 | } | ||
| 3853 | |||
| 3854 |
7/8✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 300 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 321 times.
|
329 | if (field->type() == MYSQL_TYPE_VARCHAR && !is_multi_value) { |
| 3855 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | uint32_t length_bytes = field->get_length_bytes(); |
| 3856 | |||
| 3857 | 8 | col_len -= length_bytes; | |
| 3858 | |||
| 3859 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (length_bytes == 2) { |
| 3860 | 2 | field_type |= DATA_LONG_TRUE_VARCHAR; | |
| 3861 | } | ||
| 3862 | } | ||
| 3863 | |||
| 3864 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | ctx->add_vcol[j].m_col.prtype = dtype_form_prtype(field_type, charset_no); |
| 3865 | |||
| 3866 | 329 | ctx->add_vcol[j].m_col.prtype |= DATA_VIRTUAL; | |
| 3867 | |||
| 3868 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 233 times.
|
329 | if (is_multi_value) { |
| 3869 | 96 | ctx->add_vcol[j].m_col.prtype |= DATA_MULTI_VALUE; | |
| 3870 | } | ||
| 3871 | |||
| 3872 | 329 | ctx->add_vcol[j].m_col.mtype = col_type; | |
| 3873 | |||
| 3874 | 329 | ctx->add_vcol[j].m_col.len = col_len; | |
| 3875 | |||
| 3876 | 329 | ctx->add_vcol[j].m_col.ind = i - 1; | |
| 3877 | 329 | ctx->add_vcol[j].num_base = field->gcol_info->non_virtual_base_columns(); | |
| 3878 | 329 | ctx->add_vcol_name[j] = field->field_name; | |
| 3879 | 658 | ctx->add_vcol[j].base_col = static_cast<dict_col_t **>(mem_heap_alloc( | |
| 3880 | ctx->heap, | ||
| 3881 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | ctx->add_vcol[j].num_base * sizeof *(ctx->add_vcol[j].base_col))); |
| 3882 | 329 | ctx->add_vcol[j].v_pos = | |
| 3883 | 329 | ctx->old_table->n_v_cols - ha_alter_info->virtual_column_drop_count + j; | |
| 3884 | |||
| 3885 | /* No need to track the list */ | ||
| 3886 | 329 | ctx->add_vcol[j].v_indexes = nullptr; | |
| 3887 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | innodb_base_col_setup(ctx->old_table, field, &ctx->add_vcol[j]); |
| 3888 | 329 | j++; | |
| 3889 | } | ||
| 3890 | |||
| 3891 | 316 | return (false); | |
| 3892 | } | ||
| 3893 | |||
| 3894 | /** Collect virtual column info for its addition | ||
| 3895 | @param[in] ha_alter_info Data used during in-place alter | ||
| 3896 | @param[in] table MySQL table as it is before the ALTER operation | ||
| 3897 | @retval true Failure | ||
| 3898 | @retval false Success */ | ||
| 3899 | 94 | static bool prepare_inplace_drop_virtual(Alter_inplace_info *ha_alter_info, | |
| 3900 | const TABLE *table) { | ||
| 3901 | ha_innobase_inplace_ctx *ctx; | ||
| 3902 | 94 | ulint j = 0; | |
| 3903 | |||
| 3904 | 94 | ctx = static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | |
| 3905 | |||
| 3906 | 188 | ctx->drop_vcol = static_cast<dict_v_col_t *>(mem_heap_alloc( | |
| 3907 | ctx->heap, | ||
| 3908 | 94 | ha_alter_info->virtual_column_drop_count * sizeof *ctx->drop_vcol)); | |
| 3909 | 188 | ctx->drop_vcol_name = static_cast<const char **>(mem_heap_alloc( | |
| 3910 | ctx->heap, | ||
| 3911 | 94 | ha_alter_info->virtual_column_drop_count * sizeof *ctx->drop_vcol_name)); | |
| 3912 | |||
| 3913 |
2/2✓ Branch 0 taken 171 times.
✓ Branch 1 taken 93 times.
|
264 | for (const Alter_drop *drop : ha_alter_info->alter_info->drop_list) { |
| 3914 | const Field *field; | ||
| 3915 | ulint old_i; | ||
| 3916 | |||
| 3917 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 100 times.
|
171 | if (drop->type != Alter_drop::COLUMN) continue; |
| 3918 | |||
| 3919 |
1/2✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
|
483 | for (old_i = 0; table->field[old_i]; old_i++) { |
| 3920 | 483 | const Field *n_field = table->field[old_i]; | |
| 3921 |
3/4✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 383 times.
|
483 | if (!my_strcasecmp(system_charset_info, n_field->field_name, |
| 3922 | drop->name)) { | ||
| 3923 | 100 | break; | |
| 3924 | } | ||
| 3925 | } | ||
| 3926 | /* SQL-layer already has checked that all columns to be dropped exist. */ | ||
| 3927 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | ut_ad(table->field[old_i]); |
| 3928 | 100 | field = table->field[old_i]; | |
| 3929 | |||
| 3930 | /* | ||
| 3931 | We don't support simultaneous removal of virtual and stored columns | ||
| 3932 | as in-place operation yet. | ||
| 3933 | */ | ||
| 3934 |
3/6✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100 times.
|
100 | ut_ad(field->gcol_info && !field->stored_in_db); |
| 3935 | |||
| 3936 | ulint col_len; | ||
| 3937 | ulint is_unsigned; | ||
| 3938 | ulint field_type; | ||
| 3939 | ulint charset_no; | ||
| 3940 | |||
| 3941 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | ulint col_type = get_innobase_type_from_mysql_type(&is_unsigned, field); |
| 3942 | |||
| 3943 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | bool is_multi_value = innobase_is_multi_value_fld(field); |
| 3944 | |||
| 3945 |
2/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
|
100 | if (!field->gcol_info || field->stored_in_db) { |
| 3946 | ✗ | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); | |
| 3947 | 1 | return (true); | |
| 3948 | } | ||
| 3949 | |||
| 3950 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 61 times.
|
100 | if (is_multi_value) { |
| 3951 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | col_len = field->key_length(); |
| 3952 | } else { | ||
| 3953 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | col_len = field->pack_length(); |
| 3954 | } | ||
| 3955 | |||
| 3956 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | field_type = (ulint)field->type(); |
| 3957 | |||
| 3958 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 98 times.
|
100 | if (!field->is_nullable()) { |
| 3959 | 2 | field_type |= DATA_NOT_NULL; | |
| 3960 | } | ||
| 3961 | |||
| 3962 |
3/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✓ Branch 3 taken 12 times.
|
100 | if (field->binary()) { |
| 3963 | 88 | field_type |= DATA_BINARY_TYPE; | |
| 3964 | } | ||
| 3965 | |||
| 3966 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 96 times.
|
100 | if (is_unsigned) { |
| 3967 | 4 | field_type |= DATA_UNSIGNED; | |
| 3968 | } | ||
| 3969 | |||
| 3970 |
3/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 64 times.
|
100 | if (dtype_is_string_type(col_type)) { |
| 3971 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | charset_no = (ulint)field->charset()->number; |
| 3972 | |||
| 3973 |
3/4✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 35 times.
|
36 | DBUG_EXECUTE_IF("ib_alter_add_virtual_fail", |
| 3974 | charset_no += MAX_CHAR_COLL_NUM;); | ||
| 3975 | |||
| 3976 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
|
36 | if (charset_no > MAX_CHAR_COLL_NUM) { |
| 3977 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); |
| 3978 | 1 | return (true); | |
| 3979 | } | ||
| 3980 | } else { | ||
| 3981 | 64 | charset_no = 0; | |
| 3982 | } | ||
| 3983 | |||
| 3984 |
7/8✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 95 times.
|
99 | if (field->type() == MYSQL_TYPE_VARCHAR && !is_multi_value) { |
| 3985 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | uint32_t length_bytes = field->get_length_bytes(); |
| 3986 | |||
| 3987 | 4 | col_len -= length_bytes; | |
| 3988 | |||
| 3989 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (length_bytes == 2) { |
| 3990 | 2 | field_type |= DATA_LONG_TRUE_VARCHAR; | |
| 3991 | } | ||
| 3992 | } | ||
| 3993 | |||
| 3994 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | ctx->drop_vcol[j].m_col.prtype = dtype_form_prtype(field_type, charset_no); |
| 3995 | |||
| 3996 | 99 | ctx->drop_vcol[j].m_col.prtype |= DATA_VIRTUAL; | |
| 3997 | |||
| 3998 | 99 | ctx->drop_vcol[j].m_col.mtype = col_type; | |
| 3999 | |||
| 4000 | 99 | ctx->drop_vcol[j].m_col.len = col_len; | |
| 4001 | |||
| 4002 | 99 | ctx->drop_vcol[j].m_col.ind = old_i; | |
| 4003 | |||
| 4004 | 99 | ctx->drop_vcol_name[j] = field->field_name; | |
| 4005 | |||
| 4006 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | dict_v_col_t *v_col = dict_table_get_nth_v_col_mysql(ctx->old_table, old_i); |
| 4007 | 99 | ctx->drop_vcol[j].v_pos = v_col->v_pos; | |
| 4008 | 99 | j++; | |
| 4009 | } | ||
| 4010 | |||
| 4011 | 93 | return (false); | |
| 4012 | } | ||
| 4013 | |||
| 4014 | /** Adjust the create index column number from "New table" to | ||
| 4015 | "old InnoDB table" while we are doing dropping virtual column. Since we do | ||
| 4016 | not create separate new table for the dropping/adding virtual columns. | ||
| 4017 | To correctly find the indexed column, we will need to find its col_no | ||
| 4018 | in the "Old Table", not the "New table". | ||
| 4019 | @param[in] ha_alter_info Data used during in-place alter | ||
| 4020 | @param[in] old_table MySQL table as it is before the ALTER operation | ||
| 4021 | @param[in] num_v_dropped number of virtual column dropped | ||
| 4022 | @param[in,out] index_def index definition */ | ||
| 4023 | 8 | static void innodb_v_adjust_idx_col(const Alter_inplace_info *ha_alter_info, | |
| 4024 | const TABLE *old_table, ulint num_v_dropped, | ||
| 4025 | ddl::Index_defn *index_def) { | ||
| 4026 | List_iterator_fast<Create_field> cf_it( | ||
| 4027 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | ha_alter_info->alter_info->create_list); |
| 4028 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
|
18 | for (ulint i = 0; i < index_def->m_n_fields; i++) { |
| 4029 | #ifdef UNIV_DEBUG | ||
| 4030 | 10 | bool col_found = false; | |
| 4031 | #endif /* UNIV_DEBUG */ | ||
| 4032 | 10 | ulint num_v = 0; | |
| 4033 | |||
| 4034 | 10 | auto index_field = &index_def->m_fields[i]; | |
| 4035 | |||
| 4036 | /* Only adjust virtual column col_no, since non-virtual | ||
| 4037 | column position (in non-vcol list) won't change unless | ||
| 4038 | table rebuild */ | ||
| 4039 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (!index_field->m_is_v_col) { |
| 4040 | 1 | continue; | |
| 4041 | } | ||
| 4042 | |||
| 4043 | 9 | const Field *field = nullptr; | |
| 4044 | |||
| 4045 | 9 | cf_it.rewind(); | |
| 4046 | |||
| 4047 | /* Found the field in the new table */ | ||
| 4048 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | while (const Create_field *new_field = cf_it++) { |
| 4049 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 10 times.
|
27 | if (!new_field->is_virtual_gcol()) { |
| 4050 | 17 | continue; | |
| 4051 | } | ||
| 4052 | |||
| 4053 | 10 | field = new_field->field; | |
| 4054 | |||
| 4055 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | if (num_v == index_field->m_col_no) { |
| 4056 | 9 | break; | |
| 4057 | } | ||
| 4058 | 1 | num_v++; | |
| 4059 | 18 | } | |
| 4060 | |||
| 4061 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (!field) { |
| 4062 | /* this means the field is a newly added field, this | ||
| 4063 | should have been blocked when we drop virtual column | ||
| 4064 | at the same time */ | ||
| 4065 | ✗ | ut_ad(num_v_dropped > 0); | |
| 4066 | ✗ | ut_error; | |
| 4067 | } | ||
| 4068 | |||
| 4069 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | ut_ad(field->is_virtual_gcol()); |
| 4070 | |||
| 4071 | 9 | num_v = 0; | |
| 4072 | |||
| 4073 | /* Look for its position in old table */ | ||
| 4074 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | for (uint old_i = 0; old_table->field[old_i]; old_i++) { |
| 4075 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 27 times.
|
36 | if (old_table->field[old_i] == field) { |
| 4076 | /* Found it, adjust its col_no to its position | ||
| 4077 | in old table */ | ||
| 4078 | 9 | index_def->m_fields[i].m_col_no = num_v; | |
| 4079 | 9 | ut_d(col_found = true); | |
| 4080 | 9 | break; | |
| 4081 | } | ||
| 4082 | |||
| 4083 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17 times.
|
27 | if (old_table->field[old_i]->is_virtual_gcol()) { |
| 4084 | 10 | num_v++; | |
| 4085 | } | ||
| 4086 | } | ||
| 4087 | |||
| 4088 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | ut_ad(col_found); |
| 4089 | } | ||
| 4090 | 8 | } | |
| 4091 | |||
| 4092 | /** Replace the table name in filename with the specified one | ||
| 4093 | @param[in] filename original file name | ||
| 4094 | @param[out] new_filename new file name | ||
| 4095 | @param[in] table_name to replace with this table name, | ||
| 4096 | in the format of db/name */ | ||
| 4097 | 17882 | static void replace_table_name(const char *filename, char *new_filename, | |
| 4098 | const char *table_name) { | ||
| 4099 | 17882 | const char *slash = strrchr(filename, OS_PATH_SEPARATOR); | |
| 4100 | 17882 | size_t len = 0; | |
| 4101 | |||
| 4102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17882 times.
|
17882 | if (slash == nullptr) { |
| 4103 | ✗ | len = 0; | |
| 4104 | } else { | ||
| 4105 | 17882 | len = slash - filename + 1; | |
| 4106 | } | ||
| 4107 | |||
| 4108 | 17882 | memcpy(new_filename, filename, len); | |
| 4109 | |||
| 4110 | 17882 | slash = strchr(table_name, '/'); | |
| 4111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17882 times.
|
17882 | ut_ad(slash != nullptr); |
| 4112 | |||
| 4113 | 17882 | strcpy(new_filename + len, slash + 1); | |
| 4114 | |||
| 4115 | 17882 | len += strlen(slash + 1); | |
| 4116 | |||
| 4117 | 17882 | strcpy(new_filename + len, dot_ext[IBD]); | |
| 4118 | 17882 | } | |
| 4119 | |||
| 4120 | /** Update the metadata in prepare phase. This only check if dd::Tablespace | ||
| 4121 | should be removed or(and) created, because to remove and store dd::Tablespace | ||
| 4122 | could fail, so it's better to do it earlier, to prevent a late rollback | ||
| 4123 | @param[in,out] thd MySQL connection | ||
| 4124 | @param[in] old_table Old InnoDB table object | ||
| 4125 | @param[in,out] new_table New InnoDB table object | ||
| 4126 | @param[in] old_dd_tab Old dd::Table or dd::Partition | ||
| 4127 | @return false On success | ||
| 4128 | @retval true On failure */ | ||
| 4129 | template <typename Table> | ||
| 4130 | 95032 | [[nodiscard]] static bool dd_prepare_inplace_alter_table( | |
| 4131 | THD *thd, const dict_table_t *old_table, dict_table_t *new_table, | ||
| 4132 | const Table *old_dd_tab) { | ||
| 4133 |
7/8✓ Branch 0 taken 47516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47506 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 17146 times.
✓ Branch 5 taken 30360 times.
✓ Branch 6 taken 17156 times.
✓ Branch 7 taken 30360 times.
|
95032 | if (new_table->is_temporary() || old_table == new_table) { |
| 4134 | /* No need to fill in metadata for temporary tables, | ||
| 4135 | which would not be stored in Global DD */ | ||
| 4136 | 34312 | return false; | |
| 4137 | } | ||
| 4138 | |||
| 4139 |
1/2✓ Branch 0 taken 30360 times.
✗ Branch 1 not taken.
|
60720 | dd::cache::Dictionary_client *client = dd::get_dd_client(thd); |
| 4140 |
1/2✓ Branch 0 taken 30360 times.
✗ Branch 1 not taken.
|
60720 | dd::cache::Dictionary_client::Auto_releaser releaser(client); |
| 4141 | |||
| 4142 | 60720 | uint64_t autoextend_size{}; | |
| 4143 | |||
| 4144 |
3/4✓ Branch 0 taken 30360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19651 times.
✓ Branch 3 taken 10709 times.
|
60720 | if (dict_table_is_file_per_table(old_table)) { |
| 4145 |
2/4✓ Branch 0 taken 19651 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19651 times.
✗ Branch 3 not taken.
|
39302 | dd::Object_id old_space_id = dd_first_index(old_dd_tab)->tablespace_id(); |
| 4146 | |||
| 4147 | /* Copy the autoextend_size attribute value for the tablespace being | ||
| 4148 | dropped. This value will be copied to the new tablespace created later. */ | ||
| 4149 |
2/4✓ Branch 0 taken 19651 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19651 times.
|
39302 | if (dd_get_tablespace_size_option(client, old_space_id, &autoextend_size)) { |
| 4150 | ✗ | return true; | |
| 4151 | } | ||
| 4152 | |||
| 4153 |
2/4✓ Branch 0 taken 19651 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19651 times.
|
39302 | if (dd_drop_tablespace(client, old_space_id)) { |
| 4154 | ✗ | return true; | |
| 4155 | } | ||
| 4156 | } | ||
| 4157 | |||
| 4158 |
3/4✓ Branch 0 taken 30360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17882 times.
✓ Branch 3 taken 12478 times.
|
60720 | if (dict_table_is_file_per_table(new_table)) { |
| 4159 | /* Replace the table name with the final correct one */ | ||
| 4160 |
1/2✓ Branch 0 taken 17882 times.
✗ Branch 1 not taken.
|
35764 | char *path = fil_space_get_first_path(new_table->space); |
| 4161 | char filename[FN_REFLEN + 1]; | ||
| 4162 |
1/2✓ Branch 0 taken 17882 times.
✗ Branch 1 not taken.
|
35764 | replace_table_name(path, filename, old_table->name.m_name); |
| 4163 | 35764 | ut::free(path); | |
| 4164 | |||
| 4165 | 35764 | bool discarded = false; | |
| 4166 |
3/4✓ Branch 0 taken 17882 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17765 times.
✓ Branch 3 taken 117 times.
|
35764 | if (dict_table_is_file_per_table(old_table)) { |
| 4167 |
1/2✓ Branch 0 taken 17765 times.
✗ Branch 1 not taken.
|
35530 | discarded = dd_is_discarded(*old_dd_tab); |
| 4168 | } | ||
| 4169 | |||
| 4170 | dd::Object_id dd_space_id; | ||
| 4171 | |||
| 4172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17882 times.
|
35764 | if (dd_create_implicit_tablespace(client, new_table->space, |
| 4173 |
1/2✓ Branch 0 taken 17882 times.
✗ Branch 1 not taken.
|
35764 | old_table->name.m_name, filename, |
| 4174 | discarded, dd_space_id)) { | ||
| 4175 | ✗ | my_error(ER_INTERNAL_ERROR, MYF(0), | |
| 4176 | " InnoDB can't create tablespace object" | ||
| 4177 | " for ", | ||
| 4178 | new_table->name); | ||
| 4179 | ✗ | return true; | |
| 4180 | } | ||
| 4181 | |||
| 4182 | 35764 | new_table->dd_space_id = dd_space_id; | |
| 4183 | } | ||
| 4184 | |||
| 4185 | 60720 | return false; | |
| 4186 | 60720 | } | |
| 4187 | |||
| 4188 | /** Update table level instant metadata in commit phase of INPLACE ALTER | ||
| 4189 | @param[in] table InnoDB table object | ||
| 4190 | @param[in] old_dd_tab old dd::Table | ||
| 4191 | @param[in] new_dd_tab new dd::Table */ | ||
| 4192 | 16562 | static void dd_commit_inplace_update_instant_meta(const dict_table_t *table, | |
| 4193 | const dd::Table *old_dd_tab, | ||
| 4194 | dd::Table *new_dd_tab) { | ||
| 4195 | /** If table->skip_alter_undo is true during inplace, it is expanded fast | ||
| 4196 | index creation. The inplace ALTERs for that can only be about DROP INDEX | ||
| 4197 | and ADD INDEX and can never be instant operations */ | ||
| 4198 |
6/6✓ Branch 0 taken 16553 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 16547 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 16556 times.
✓ Branch 5 taken 6 times.
|
16562 | if (table->skip_alter_undo || !dd_table_has_instant_cols(*old_dd_tab)) { |
| 4199 | 16556 | return; | |
| 4200 | } | ||
| 4201 | |||
| 4202 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
6 | ut_ad(table->has_instant_cols() || table->has_row_versions()); |
| 4203 | |||
| 4204 | 6 | const char *s = dd_table_key_strings[DD_TABLE_INSTANT_COLS]; | |
| 4205 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
6 | if (old_dd_tab->se_private_data().exists(s)) { |
| 4206 | ✗ | ut_ad(table->is_upgraded_instant()); | |
| 4207 | ✗ | uint32_t value = 0; | |
| 4208 | ✗ | old_dd_tab->se_private_data().get(s, &value); | |
| 4209 | ✗ | new_dd_tab->se_private_data().set(s, value); | |
| 4210 | } | ||
| 4211 | |||
| 4212 | /* Copy instant default values of columns if exists */ | ||
| 4213 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 6 times.
|
66 | for (uint16_t i = 0; i < table->get_n_user_cols(); ++i) { |
| 4214 | 60 | const dict_col_t *col = table->get_col(i); | |
| 4215 | |||
| 4216 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
|
60 | if (col->instant_default == nullptr) { |
| 4217 | 54 | continue; | |
| 4218 | } | ||
| 4219 | |||
| 4220 | dd::Column *dd_col = const_cast<dd::Column *>( | ||
| 4221 | 6 | dd_find_column(new_dd_tab, table->get_col_name(i))); | |
| 4222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | ut_ad(dd_col != nullptr); |
| 4223 | |||
| 4224 | 6 | dd_write_default_value(col, dd_col); | |
| 4225 | } | ||
| 4226 | } | ||
| 4227 | |||
| 4228 | /** Update metadata in commit phase. Note this function should only update | ||
| 4229 | the metadata which would not result in failure | ||
| 4230 | @param[in] old_info Some table information for the old table | ||
| 4231 | @param[in,out] new_table New InnoDB table object | ||
| 4232 | @param[in] old_dd_tab Old dd::Table or dd::Partition | ||
| 4233 | @param[in,out] new_dd_tab New dd::Table or dd::Partition */ | ||
| 4234 | template <typename Table> | ||
| 4235 | 94142 | static void dd_commit_inplace_alter_table( | |
| 4236 | const alter_table_old_info_t &old_info, dict_table_t *new_table, | ||
| 4237 | const Table *old_dd_tab, Table *new_dd_tab) { | ||
| 4238 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 47062 times.
|
94142 | if (new_table->is_temporary()) { |
| 4239 | /* No need to fill in metadata for temporary tables, | ||
| 4240 | which would not be stored in Global DD */ | ||
| 4241 | 18 | return; | |
| 4242 | } | ||
| 4243 | |||
| 4244 | dd::Object_id dd_space_id; | ||
| 4245 | |||
| 4246 |
2/2✓ Branch 0 taken 30071 times.
✓ Branch 1 taken 16991 times.
|
94124 | if (old_info.m_rebuild) { |
| 4247 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30071 times.
|
60142 | ut_ad(!new_table->has_instant_cols()); |
| 4248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30071 times.
|
60142 | ut_ad(!new_table->has_row_versions()); |
| 4249 | |||
| 4250 |
2/2✓ Branch 0 taken 17611 times.
✓ Branch 1 taken 12460 times.
|
60142 | if (dict_table_is_file_per_table(new_table)) { |
| 4251 | /* Get the one created in prepare phase */ | ||
| 4252 | 35222 | dd_space_id = new_table->dd_space_id; | |
| 4253 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 12368 times.
|
24920 | } else if (new_table->space == TRX_SYS_SPACE) { |
| 4254 | 184 | dd_space_id = dict_sys_t::s_dd_sys_space_id; | |
| 4255 | } else { | ||
| 4256 | /* Currently, even if specifying a new TABLESPACE | ||
| 4257 | for partitioned table, existing partitions would not | ||
| 4258 | be moved to new tablespaces. Thus, the old | ||
| 4259 | tablespace id should still be used for new partition */ | ||
| 4260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12368 times.
|
24736 | if (dd_table_is_partitioned(new_dd_tab->table())) { |
| 4261 | ✗ | dd_space_id = dd_first_index(old_dd_tab)->tablespace_id(); | |
| 4262 | } else { | ||
| 4263 | 24736 | dd_space_id = dd_get_space_id(new_dd_tab->table()); | |
| 4264 | } | ||
| 4265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12368 times.
|
24736 | ut_ad(dd_space_id != dd::INVALID_OBJECT_ID); |
| 4266 | } | ||
| 4267 | } else { | ||
| 4268 |
4/4✓ Branch 0 taken 433 times.
✓ Branch 1 taken 16558 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 16905 times.
|
34848 | if (old_info.m_fts_doc_id && |
| 4269 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 347 times.
|
866 | !dd_find_column(&new_dd_tab->table(), FTS_DOC_ID_COL_NAME)) { |
| 4270 | dd::Column *col = | ||
| 4271 | 172 | dd_add_hidden_column(&new_dd_tab->table(), FTS_DOC_ID_COL_NAME, | |
| 4272 | FTS_DOC_ID_LEN, dd::enum_column_types::LONGLONG); | ||
| 4273 | |||
| 4274 | 172 | dd_set_hidden_unique_index(new_dd_tab->table().add_index(), | |
| 4275 | FTS_DOC_ID_INDEX_NAME, col); | ||
| 4276 | } | ||
| 4277 | |||
| 4278 | /* This can happen only with expanded fast index creation. On the | ||
| 4279 | intermediate table during ALTER COPY, we drop secondary indexes using | ||
| 4280 | inplace alter APIs. The old definition here is old copy of table. Hence we | ||
| 4281 | should use new_dd_tab here for updating the dd::Indexes */ | ||
| 4282 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16991 times.
|
33982 | if (new_table->skip_alter_undo) { |
| 4283 | ✗ | dd_space_id = dd_first_index(new_dd_tab)->tablespace_id(); | |
| 4284 | } else { | ||
| 4285 | 33982 | dd_space_id = dd_first_index(old_dd_tab)->tablespace_id(); | |
| 4286 | } | ||
| 4287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16991 times.
|
33982 | ut_ad(dd_space_id != dd::INVALID_OBJECT_ID); |
| 4288 | } | ||
| 4289 | |||
| 4290 | 94124 | dd_set_table_options(new_dd_tab, new_table); | |
| 4291 | |||
| 4292 | 94124 | new_table->dd_space_id = dd_space_id; | |
| 4293 | |||
| 4294 | 94124 | dd_write_table(dd_space_id, new_dd_tab, new_table); | |
| 4295 | |||
| 4296 | /* If this table is discarded, we need to set this to both dd::Table | ||
| 4297 | and dd::Tablespace. */ | ||
| 4298 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 47051 times.
|
94124 | if (old_info.m_discarded) { |
| 4299 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | dd_set_discarded(*new_dd_tab, true); |
| 4300 | |||
| 4301 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | THD *thd = current_thd; |
| 4302 | dd::Object_id dd_space_id = | ||
| 4303 |
4/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
|
22 | (*new_dd_tab->indexes()->begin())->tablespace_id(); |
| 4304 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | std::string space_name(new_table->name.m_name); |
| 4305 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | dict_name::convert_to_space(space_name); |
| 4306 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
22 | dd_tablespace_set_state(thd, dd_space_id, space_name, |
| 4307 | DD_SPACE_STATE_DISCARDED); | ||
| 4308 | } | ||
| 4309 | } | ||
| 4310 | |||
| 4311 | template <typename Table> | ||
| 4312 | ✗ | static void dd_commit_inplace_no_change(const Alter_inplace_info *ha_alter_info, | |
| 4313 | const Table *old_dd_tab, | ||
| 4314 | Table *new_dd_tab, bool ignore_fts) { | ||
| 4315 | ✗ | if (!ignore_fts) { | |
| 4316 | ✗ | dd_add_fts_doc_id_index(new_dd_tab->table(), old_dd_tab->table()); | |
| 4317 | } | ||
| 4318 | |||
| 4319 | ✗ | dd_copy_private(*new_dd_tab, *old_dd_tab); | |
| 4320 | |||
| 4321 | ✗ | if (!dd_table_is_partitioned(new_dd_tab->table()) || | |
| 4322 | ✗ | dd_part_is_first(reinterpret_cast<dd::Partition *>(new_dd_tab))) { | |
| 4323 | ✗ | dd_copy_table(ha_alter_info, new_dd_tab->table(), old_dd_tab->table()); | |
| 4324 | } | ||
| 4325 | } | ||
| 4326 | |||
| 4327 | /** Check if a new table's index will exceed the index limit for the table | ||
| 4328 | row format | ||
| 4329 | @param[in] form MySQL table that is being altered | ||
| 4330 | @param[in] max_len max index length allowed | ||
| 4331 | @return true if within limits false otherwise */ | ||
| 4332 | 37 | static bool innobase_check_index_len(const TABLE *form, ulint max_len) { | |
| 4333 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 37 times.
|
59 | for (uint key_num = 0; key_num < form->s->keys; key_num++) { |
| 4334 | 22 | const KEY &key = form->key_info[key_num]; | |
| 4335 | |||
| 4336 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 22 times.
|
47 | for (unsigned i = 0; i < key.user_defined_key_parts; i++) { |
| 4337 | 25 | const KEY_PART_INFO *key_part = &key.key_part[i]; | |
| 4338 | 25 | unsigned prefix_len = 0; | |
| 4339 | |||
| 4340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (key.flags & HA_SPATIAL) { |
| 4341 | ✗ | prefix_len = 0; | |
| 4342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | } else if (key.flags & HA_FULLTEXT) { |
| 4343 | ✗ | prefix_len = 0; | |
| 4344 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 22 times.
|
25 | } else if (key_part->key_part_flag & HA_PART_KEY_SEG) { |
| 4345 | /* SPATIAL and FULLTEXT index always are on | ||
| 4346 | full columns. */ | ||
| 4347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | ut_ad(!(key.flags & (HA_SPATIAL | HA_FULLTEXT))); |
| 4348 | 3 | prefix_len = key_part->length; | |
| 4349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | ut_ad(prefix_len > 0); |
| 4350 | } else { | ||
| 4351 | 22 | prefix_len = 0; | |
| 4352 | } | ||
| 4353 | |||
| 4354 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
|
25 | if (key_part->length > max_len || prefix_len > max_len) { |
| 4355 | ✗ | return (false); | |
| 4356 | } | ||
| 4357 | } | ||
| 4358 | } | ||
| 4359 | 37 | return (true); | |
| 4360 | } | ||
| 4361 | |||
| 4362 | /** Update internal structures with concurrent writes blocked, | ||
| 4363 | while preparing ALTER TABLE. | ||
| 4364 | |||
| 4365 | @param ha_alter_info Data used during in-place alter | ||
| 4366 | @param altered_table MySQL table that is being altered | ||
| 4367 | @param old_table MySQL table as it is before the ALTER operation | ||
| 4368 | @param old_dd_tab old dd table | ||
| 4369 | @param new_dd_tab new dd table | ||
| 4370 | @param table_name Table name in MySQL | ||
| 4371 | @param flags Table and tablespace flags | ||
| 4372 | @param flags2 Additional table flags | ||
| 4373 | @param fts_doc_id_col The column number of FTS_DOC_ID | ||
| 4374 | @param add_fts_doc_id Flag: add column FTS_DOC_ID? | ||
| 4375 | @param add_fts_doc_id_idx Flag: add index FTS_DOC_ID_INDEX (FTS_DOC_ID)? | ||
| 4376 | |||
| 4377 | @retval true Failure | ||
| 4378 | @retval false Success */ | ||
| 4379 | template <typename Table> | ||
| 4380 | 71524 | [[nodiscard]] static bool prepare_inplace_alter_table_dict( | |
| 4381 | Alter_inplace_info *ha_alter_info, const TABLE *altered_table, | ||
| 4382 | const TABLE *old_table, const Table *old_dd_tab, Table *new_dd_tab, | ||
| 4383 | const char *table_name, uint32_t flags, uint32_t flags2, | ||
| 4384 | ulint fts_doc_id_col, bool add_fts_doc_id, bool add_fts_doc_id_idx, | ||
| 4385 | row_prebuilt_t *prebuilt) { | ||
| 4386 | 71524 | bool dict_locked = false; | |
| 4387 | ulint *add_key_nums; /* MySQL key numbers */ | ||
| 4388 | ddl::Index_defn *index_defs; /* index definitions */ | ||
| 4389 | dict_table_t *user_table; | ||
| 4390 | 71524 | dict_index_t *fts_index = nullptr; | |
| 4391 | dberr_t error; | ||
| 4392 | ulint num_fts_index; | ||
| 4393 | 71524 | dict_add_v_col_t *add_v = nullptr; | |
| 4394 | dict_table_t *table; | ||
| 4395 | 71524 | MDL_ticket *mdl = nullptr; | |
| 4396 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | THD *thd = current_thd; |
| 4397 | 71524 | bool build_fts_common = false; | |
| 4398 | |||
| 4399 | ha_innobase_inplace_ctx *ctx; | ||
| 4400 | 71524 | KeyringEncryptionKeyIdInfo keyring_encryption_key_id; | |
| 4401 | 71524 | bool none_explicitly_specified = Encryption::none_explicitly_specified( | |
| 4402 | 71524 | ha_alter_info->create_info->explicit_encryption, | |
| 4403 | 71524 | ha_alter_info->create_info->encrypt_type.str); | |
| 4404 | |||
| 4405 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | DBUG_TRACE; |
| 4406 | |||
| 4407 | 71524 | ctx = static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | |
| 4408 | |||
| 4409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert((ctx->add_autoinc != ULINT_UNDEFINED) == |
| 4410 | (ctx->sequence.m_max_value > 0)); | ||
| 4411 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->num_to_drop_index == !ctx->drop_index); |
| 4412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->num_to_drop_fk == !ctx->drop_fk); |
| 4413 |
3/4✓ Branch 0 taken 122 times.
✓ Branch 1 taken 35640 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 122 times.
|
71524 | assert(!add_fts_doc_id || add_fts_doc_id_idx); |
| 4414 |
3/4✓ Branch 0 taken 137 times.
✓ Branch 1 taken 35625 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 137 times.
|
71524 | assert(!add_fts_doc_id_idx || innobase_fulltext_exist(altered_table)); |
| 4415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->add_cols); |
| 4416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->add_index); |
| 4417 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->add_key_numbers); |
| 4418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ctx->num_to_add_index); |
| 4419 | |||
| 4420 | 71524 | user_table = ctx->new_table; | |
| 4421 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | bool is_file_per_table = dict_table_is_file_per_table(user_table); |
| 4422 | |||
| 4423 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | trx_start_if_not_started_xa(ctx->prebuilt->trx, true, UT_LOCATION_HERE); |
| 4424 | |||
| 4425 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 35755 times.
|
71524 | if (ha_alter_info->handler_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN) { |
| 4426 |
3/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
|
14 | if (prepare_inplace_drop_virtual(ha_alter_info, old_table)) { |
| 4427 | 2 | return true; | |
| 4428 | } | ||
| 4429 | } | ||
| 4430 | |||
| 4431 |
2/2✓ Branch 0 taken 170 times.
✓ Branch 1 taken 35591 times.
|
71522 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_VIRTUAL_COLUMN) { |
| 4432 |
3/4✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 169 times.
|
340 | if (prepare_inplace_add_virtual(ha_alter_info, altered_table, old_table)) { |
| 4433 | 2 | return true; | |
| 4434 | } | ||
| 4435 | |||
| 4436 | /* Need information for newly added virtual columns | ||
| 4437 | for create index */ | ||
| 4438 |
1/2✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
|
338 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX) { |
| 4439 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 169 times.
|
702 | for (ulint i = 0; i < ha_alter_info->virtual_column_add_count; i++) { |
| 4440 | /* Set mbminmax for newly added column */ | ||
| 4441 | ulint i_mbminlen, i_mbmaxlen; | ||
| 4442 | 364 | dtype_get_mblen(ctx->add_vcol[i].m_col.mtype, | |
| 4443 |
1/2✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
|
364 | ctx->add_vcol[i].m_col.prtype, &i_mbminlen, |
| 4444 | &i_mbmaxlen); | ||
| 4445 | |||
| 4446 |
1/2✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
|
364 | ctx->add_vcol[i].m_col.set_mbminmaxlen(i_mbminlen, i_mbmaxlen); |
| 4447 | } | ||
| 4448 | add_v = static_cast<dict_add_v_col_t *>( | ||
| 4449 |
1/2✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
|
338 | mem_heap_alloc(ctx->heap, sizeof *add_v)); |
| 4450 | 338 | add_v->n_v_col = ha_alter_info->virtual_column_add_count; | |
| 4451 | 338 | add_v->v_col = ctx->add_vcol; | |
| 4452 | 338 | add_v->v_col_name = ctx->add_vcol_name; | |
| 4453 | } | ||
| 4454 | } | ||
| 4455 | |||
| 4456 |
2/2✓ Branch 0 taken 15049 times.
✓ Branch 1 taken 20711 times.
|
71520 | if ((ha_alter_info->handler_flags & |
| 4457 | 30098 | Alter_inplace_info::CHANGE_CREATE_OPTION) && | |
| 4458 |
2/2✓ Branch 0 taken 10320 times.
✓ Branch 1 taken 4729 times.
|
30098 | !(ha_alter_info->create_info->used_fields & HA_CREATE_USED_TABLESPACE) && |
| 4459 | 20640 | ha_alter_info->create_info | |
| 4460 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10318 times.
|
20640 | ->m_implicit_tablespace_autoextend_size_change) { |
| 4461 | /* Update the autoextend_size value in the data dictionary. Do not update | ||
| 4462 | if the table is being moved to a new tablespace. The autoextend_size value | ||
| 4463 | for the new tablespace will be updated later. */ | ||
| 4464 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
4 | if (prepare_inplace_change_implicit_tablespace_option( |
| 4465 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | ctx->prebuilt->trx->mysql_thd, ha_alter_info, ctx->old_table)) { |
| 4466 | ✗ | return true; | |
| 4467 | } | ||
| 4468 | } | ||
| 4469 | |||
| 4470 | /* There should be no order change for virtual columns coming in | ||
| 4471 | here */ | ||
| 4472 |
2/4✓ Branch 0 taken 35760 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35760 times.
|
71520 | ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info)); |
| 4473 | |||
| 4474 | 71520 | ctx->trx = ctx->prebuilt->trx; | |
| 4475 | |||
| 4476 | /* Create table containing all indexes to be built in this | ||
| 4477 | ALTER TABLE ADD INDEX so that they are in the correct order | ||
| 4478 | in the table. */ | ||
| 4479 | |||
| 4480 | 71520 | ctx->num_to_add_index = ha_alter_info->index_add_count; | |
| 4481 | |||
| 4482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35760 times.
|
71520 | ut_ad(ctx->prebuilt->trx->mysql_thd != nullptr); |
| 4483 |
1/2✓ Branch 0 taken 35760 times.
✗ Branch 1 not taken.
|
71520 | const char *path = thd_innodb_tmpdir(ctx->prebuilt->trx->mysql_thd); |
| 4484 | |||
| 4485 | 214560 | index_defs = innobase_create_key_defs( | |
| 4486 | ctx->heap, ha_alter_info, altered_table, new_dd_tab, | ||
| 4487 | 71520 | ctx->num_to_add_index, num_fts_index, | |
| 4488 |
2/4✓ Branch 0 taken 35760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35760 times.
✗ Branch 3 not taken.
|
71520 | row_table_got_default_clust_index(ctx->new_table), fts_doc_id_col, |
| 4489 | add_fts_doc_id, add_fts_doc_id_idx, old_table, is_file_per_table); | ||
| 4490 | |||
| 4491 | 71520 | bool new_clustered = DICT_CLUSTERED & index_defs[0].m_ind_type; | |
| 4492 | |||
| 4493 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35758 times.
|
71520 | if (num_fts_index > 1) { |
| 4494 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_INNODB_FT_LIMIT, MYF(0)); |
| 4495 | 4 | goto error_handled; | |
| 4496 | } | ||
| 4497 | |||
| 4498 |
2/2✓ Branch 0 taken 30467 times.
✓ Branch 1 taken 5291 times.
|
71516 | if (new_clustered) { |
| 4499 | /* If max index length is reduced due to row format change | ||
| 4500 | make sure the index can all be accomodated in new row format */ | ||
| 4501 | 60934 | ulint max_len = DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags); | |
| 4502 | |||
| 4503 |
4/4✓ Branch 0 taken 30292 times.
✓ Branch 1 taken 175 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 30430 times.
|
60934 | if (max_len < DICT_MAX_FIELD_LEN_BY_FORMAT(ctx->old_table)) { |
| 4504 |
2/4✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
|
74 | if (!innobase_check_index_len(altered_table, max_len)) { |
| 4505 | ✗ | my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), max_len); | |
| 4506 | ✗ | goto error_handled; | |
| 4507 | } | ||
| 4508 | } | ||
| 4509 | } | ||
| 4510 | |||
| 4511 |
2/2✓ Branch 0 taken 34869 times.
✓ Branch 1 taken 889 times.
|
71516 | if (!ctx->online) { |
| 4512 | /* This is not an online operation (LOCK=NONE). */ | ||
| 4513 |
3/6✓ Branch 0 taken 34869 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34869 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34869 times.
|
139476 | } else if (ctx->add_autoinc == ULINT_UNDEFINED && num_fts_index == 0 && |
| 4514 |
2/2✓ Branch 0 taken 30175 times.
✓ Branch 1 taken 4694 times.
|
69738 | (!innobase_need_rebuild(ha_alter_info, old_table, |
| 4515 | 60350 | is_file_per_table) || | |
| 4516 |
1/2✓ Branch 0 taken 30175 times.
✗ Branch 1 not taken.
|
60350 | !innobase_fulltext_exist(altered_table))) { |
| 4517 | /* InnoDB can perform an online operation (LOCK=NONE). */ | ||
| 4518 | } else { | ||
| 4519 | /* This should have been blocked in | ||
| 4520 | check_if_supported_inplace_alter(). */ | ||
| 4521 | ✗ | my_error(ER_NOT_SUPPORTED_YET, MYF(0), | |
| 4522 | ✗ | thd_query_unsafe(ctx->prebuilt->trx->mysql_thd).str); | |
| 4523 | ✗ | ut_d(ut_error); | |
| 4524 | ut_o(goto error_handled); | ||
| 4525 | } | ||
| 4526 | |||
| 4527 | /* The primary index would be rebuilt if a FTS Doc ID | ||
| 4528 | column is to be added, and the primary index definition | ||
| 4529 | is just copied from old table and stored in indexdefs[0] */ | ||
| 4530 |
3/4✓ Branch 0 taken 122 times.
✓ Branch 1 taken 35636 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 122 times.
|
71516 | assert(!add_fts_doc_id || new_clustered); |
| 4531 |
5/6✓ Branch 0 taken 5410 times.
✓ Branch 1 taken 30348 times.
✓ Branch 2 taken 119 times.
✓ Branch 3 taken 5291 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 35758 times.
|
71516 | assert( |
| 4532 | new_clustered == | ||
| 4533 | (innobase_need_rebuild(ha_alter_info, old_table, is_file_per_table) || | ||
| 4534 | add_fts_doc_id)); | ||
| 4535 | |||
| 4536 | /* Allocate memory for dictionary index definitions */ | ||
| 4537 | |||
| 4538 | 143032 | ctx->add_index = static_cast<dict_index_t **>(mem_heap_alloc( | |
| 4539 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | ctx->heap, ctx->num_to_add_index * sizeof *ctx->add_index)); |
| 4540 | 143032 | ctx->add_key_numbers = add_key_nums = static_cast<ulint *>(mem_heap_alloc( | |
| 4541 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | ctx->heap, ctx->num_to_add_index * sizeof *ctx->add_key_numbers)); |
| 4542 | |||
| 4543 | /* Acquire a lock on the table before creating any indexes. */ | ||
| 4544 |
2/2✓ Branch 0 taken 34869 times.
✓ Branch 1 taken 889 times.
|
71516 | if (ctx->online) { |
| 4545 | 69738 | error = DB_SUCCESS; | |
| 4546 | } else { | ||
| 4547 | 1778 | error = ddl::lock_table(ctx->prebuilt->trx, ctx->new_table, LOCK_S); | |
| 4548 | |||
| 4549 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 889 times.
|
1778 | if (error != DB_SUCCESS) { |
| 4550 | ✗ | goto error_handling; | |
| 4551 | } | ||
| 4552 | } | ||
| 4553 | |||
| 4554 | /* Latch the InnoDB data dictionary exclusively so that no deadlocks | ||
| 4555 | or lock waits can happen in it during an index create operation. */ | ||
| 4556 | |||
| 4557 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | row_mysql_lock_data_dictionary(ctx->prebuilt->trx, UT_LOCATION_HERE); |
| 4558 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35758 times.
|
71516 | ut_ad(ctx->trx == ctx->prebuilt->trx); |
| 4559 | 71516 | dict_locked = true; | |
| 4560 | |||
| 4561 | /* Wait for background stats processing to stop using the table that | ||
| 4562 | we are going to alter. We know bg stats will not start using it again | ||
| 4563 | until we are holding the data dict locked and we are holding it here | ||
| 4564 | at least until checking ut_ad(user_table->n_ref_count == 1) below. | ||
| 4565 | XXX what may happen if bg stats opens the table after we | ||
| 4566 | have unlocked data dictionary below? */ | ||
| 4567 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | dict_stats_wait_bg_to_stop_using_table(user_table, ctx->trx); |
| 4568 | |||
| 4569 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | online_retry_drop_dict_indexes(ctx->new_table, true); |
| 4570 | |||
| 4571 |
1/2✓ Branch 0 taken 35758 times.
✗ Branch 1 not taken.
|
71516 | ut_d(dict_table_check_for_dup_indexes(ctx->new_table, CHECK_ABORTED_OK)); |
| 4572 | |||
| 4573 | /* If a new clustered index is defined for the table we need | ||
| 4574 | to rebuild the table with a temporary name. */ | ||
| 4575 | |||
| 4576 |
2/2✓ Branch 0 taken 30467 times.
✓ Branch 1 taken 5291 times.
|
71516 | if (new_clustered) { |
| 4577 | 121868 | const char *new_table_name = dict_mem_create_temporary_tablename( | |
| 4578 |
1/2✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
|
60934 | ctx->heap, ctx->new_table->name.m_name, ctx->new_table->id); |
| 4579 | 60934 | ulint n_cols = 0; | |
| 4580 | 60934 | ulint n_v_cols = 0; | |
| 4581 | 60934 | ulint n_m_v_cols = 0; | |
| 4582 | dtuple_t *add_cols; | ||
| 4583 | 60934 | space_id_t space_id = 0; | |
| 4584 | 60934 | ulint key_id = FIL_DEFAULT_ENCRYPTION_KEY; | |
| 4585 | 60934 | fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT; | |
| 4586 | |||
| 4587 | /* SQL-layer already has checked that we are not dropping any | ||
| 4588 | columns in foreign keys to be kept or making referencing column | ||
| 4589 | in a foreign key with SET NULL action non-nullable. So no need to | ||
| 4590 | check this here. */ | ||
| 4591 | |||
| 4592 |
2/2✓ Branch 0 taken 226070 times.
✓ Branch 1 taken 30467 times.
|
513074 | for (uint i = 0; i < altered_table->s->fields; i++) { |
| 4593 | 452140 | const Field *field = altered_table->field[i]; | |
| 4594 | |||
| 4595 |
4/4✓ Branch 0 taken 859 times.
✓ Branch 1 taken 225211 times.
✓ Branch 2 taken 837 times.
✓ Branch 3 taken 22 times.
|
452140 | if (innobase_is_v_fld(field)) { |
| 4596 | 1674 | n_v_cols++; | |
| 4597 |
3/4✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 835 times.
|
1674 | if (innobase_is_multi_value_fld(field)) { |
| 4598 | 4 | n_m_v_cols++; | |
| 4599 | } | ||
| 4600 | } else { | ||
| 4601 | 450466 | n_cols++; | |
| 4602 | } | ||
| 4603 | } | ||
| 4604 | |||
| 4605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30467 times.
|
60934 | ut_ad(n_cols + n_v_cols == altered_table->s->fields); |
| 4606 | |||
| 4607 |
2/2✓ Branch 0 taken 122 times.
✓ Branch 1 taken 30345 times.
|
60934 | if (add_fts_doc_id) { |
| 4608 | 244 | n_cols++; | |
| 4609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
|
244 | assert(flags2 & DICT_TF2_FTS); |
| 4610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
|
244 | assert(add_fts_doc_id_idx); |
| 4611 | 244 | flags2 |= | |
| 4612 | DICT_TF2_FTS_ADD_DOC_ID | DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS; | ||
| 4613 | } | ||
| 4614 | |||
| 4615 |
3/4✓ Branch 0 taken 123 times.
✓ Branch 1 taken 30344 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
|
60934 | assert(!add_fts_doc_id_idx || (flags2 & DICT_TF2_FTS)); |
| 4616 | |||
| 4617 | /* Create the table. */ | ||
| 4618 |
1/2✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
|
60934 | table = dd_table_open_on_name(thd, &mdl, new_table_name, true, |
| 4619 | DICT_ERR_IGNORE_NONE); | ||
| 4620 | |||
| 4621 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30467 times.
|
60934 | if (table) { |
| 4622 | ✗ | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_name); | |
| 4623 | ✗ | dd_table_close(table, thd, &mdl, true); | |
| 4624 | ✗ | goto new_clustered_failed; | |
| 4625 | } | ||
| 4626 | |||
| 4627 | /* Use the old tablespace unless the tablespace | ||
| 4628 | is changing. */ | ||
| 4629 |
4/4✓ Branch 0 taken 10695 times.
✓ Branch 1 taken 19772 times.
✓ Branch 2 taken 10478 times.
✓ Branch 3 taken 19989 times.
|
82324 | if (DICT_TF_HAS_SHARED_SPACE(user_table->flags) && |
| 4630 |
1/2✓ Branch 0 taken 10695 times.
✗ Branch 1 not taken.
|
21390 | (ha_alter_info->create_info->tablespace == nullptr || |
| 4631 |
2/2✓ Branch 0 taken 10478 times.
✓ Branch 1 taken 217 times.
|
21390 | (0 == strcmp(ha_alter_info->create_info->tablespace, |
| 4632 | user_table->tablespace)))) { | ||
| 4633 | 20956 | space_id = user_table->space; | |
| 4634 |
2/2✓ Branch 0 taken 2012 times.
✓ Branch 1 taken 17977 times.
|
39978 | } else if (tablespace_is_shared_space(ha_alter_info->create_info)) { |
| 4635 | space_id = | ||
| 4636 |
1/2✓ Branch 0 taken 2012 times.
✗ Branch 1 not taken.
|
4024 | fil_space_get_id_by_name(ha_alter_info->create_info->tablespace); |
| 4637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2012 times.
|
4024 | ut_a(space_id != SPACE_UNKNOWN); |
| 4638 | } | ||
| 4639 | |||
| 4640 | /* The initial space id 0 may be overridden later if this | ||
| 4641 | table is going to be a file_per_table tablespace. */ | ||
| 4642 | 60934 | ctx->new_table = | |
| 4643 |
1/2✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
|
60934 | dict_mem_table_create(new_table_name, space_id, n_cols + n_v_cols, |
| 4644 | n_v_cols, n_m_v_cols, flags, flags2); | ||
| 4645 | |||
| 4646 | /* TODO: Fix this problematic assignment */ | ||
| 4647 |
1/2✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
|
60934 | ctx->new_table->dd_space_id = new_dd_tab->tablespace_id(); |
| 4648 | |||
| 4649 | /* The rebuilt indexed_table will use the renamed | ||
| 4650 | column names. */ | ||
| 4651 | 60934 | ctx->col_names = nullptr; | |
| 4652 | |||
| 4653 |
2/2✓ Branch 0 taken 148 times.
✓ Branch 1 taken 30319 times.
|
60934 | if (DICT_TF_HAS_DATA_DIR(flags)) { |
| 4654 | 592 | ctx->new_table->data_dir_path = | |
| 4655 |
1/2✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
|
296 | mem_heap_strdup(ctx->new_table->heap, user_table->data_dir_path); |
| 4656 | } | ||
| 4657 | |||
| 4658 |
2/2✓ Branch 0 taken 226070 times.
✓ Branch 1 taken 30467 times.
|
513074 | for (uint i = 0; i < altered_table->s->fields; i++) { |
| 4659 | 452140 | const Field *field = altered_table->field[i]; | |
| 4660 | ulint is_unsigned; | ||
| 4661 |
1/2✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
|
452140 | ulint field_type = (ulint)field->type(); |
| 4662 |
1/2✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
|
452140 | ulint col_type = get_innobase_type_from_mysql_type(&is_unsigned, field); |
| 4663 | ulint charset_no; | ||
| 4664 | ulint col_len; | ||
| 4665 |
4/4✓ Branch 0 taken 859 times.
✓ Branch 1 taken 225211 times.
✓ Branch 2 taken 837 times.
✓ Branch 3 taken 22 times.
|
452140 | bool is_virtual = innobase_is_v_fld(field); |
| 4666 |
1/2✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
|
452140 | bool is_multi_value = innobase_is_multi_value_fld(field); |
| 4667 | |||
| 4668 | /* we assume in dtype_form_prtype() that this | ||
| 4669 | fits in two bytes */ | ||
| 4670 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 226070 times.
|
452140 | ut_a(field_type <= MAX_CHAR_COLL_NUM); |
| 4671 | |||
| 4672 |
2/2✓ Branch 0 taken 156748 times.
✓ Branch 1 taken 69322 times.
|
452140 | if (!field->is_nullable()) { |
| 4673 | 313496 | field_type |= DATA_NOT_NULL; | |
| 4674 | } | ||
| 4675 | |||
| 4676 |
3/4✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97192 times.
✓ Branch 3 taken 128878 times.
|
452140 | if (field->binary()) { |
| 4677 | 194384 | field_type |= DATA_BINARY_TYPE; | |
| 4678 | } | ||
| 4679 | |||
| 4680 |
2/2✓ Branch 0 taken 85878 times.
✓ Branch 1 taken 140192 times.
|
452140 | if (is_unsigned) { |
| 4681 | 171756 | field_type |= DATA_UNSIGNED; | |
| 4682 | } | ||
| 4683 | |||
| 4684 |
3/4✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91200 times.
✓ Branch 3 taken 134870 times.
|
452140 | if (dtype_is_string_type(col_type)) { |
| 4685 |
1/2✓ Branch 0 taken 91200 times.
✗ Branch 1 not taken.
|
182400 | charset_no = (ulint)field->charset()->number; |
| 4686 | |||
| 4687 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91200 times.
|
182400 | if (charset_no > MAX_CHAR_COLL_NUM) { |
| 4688 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4689 | ✗ | my_error(ER_WRONG_KEY_COLUMN, MYF(0), field->field_name); | |
| 4690 | ✗ | goto new_clustered_failed; | |
| 4691 | } | ||
| 4692 | } else { | ||
| 4693 | 269740 | charset_no = 0; | |
| 4694 | } | ||
| 4695 | |||
| 4696 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 226068 times.
|
452140 | if (is_multi_value) { |
| 4697 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | col_len = field->key_length(); |
| 4698 | } else { | ||
| 4699 |
1/2✓ Branch 0 taken 226068 times.
✗ Branch 1 not taken.
|
452136 | col_len = field->pack_length(); |
| 4700 | } | ||
| 4701 | |||
| 4702 | /* The MySQL pack length contains 1 or 2 bytes | ||
| 4703 | length field for a true VARCHAR. Let us | ||
| 4704 | subtract that, so that the InnoDB column | ||
| 4705 | length in the InnoDB data dictionary is the | ||
| 4706 | real maximum byte length of the actual data. */ | ||
| 4707 | |||
| 4708 |
7/8✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9929 times.
✓ Branch 3 taken 216141 times.
✓ Branch 4 taken 9927 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 9927 times.
✓ Branch 7 taken 216143 times.
|
452140 | if (field->type() == MYSQL_TYPE_VARCHAR && !is_multi_value) { |
| 4709 |
1/2✓ Branch 0 taken 9927 times.
✗ Branch 1 not taken.
|
19854 | uint32_t length_bytes = field->get_length_bytes(); |
| 4710 | |||
| 4711 | 19854 | col_len -= length_bytes; | |
| 4712 | |||
| 4713 |
2/2✓ Branch 0 taken 4517 times.
✓ Branch 1 taken 5410 times.
|
19854 | if (length_bytes == 2) { |
| 4714 | 9034 | field_type |= DATA_LONG_TRUE_VARCHAR; | |
| 4715 | } | ||
| 4716 | } | ||
| 4717 | |||
| 4718 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 226065 times.
|
452140 | if (field->column_format() == COLUMN_FORMAT_TYPE_COMPRESSED) |
| 4719 | 10 | field_type |= DATA_COMPRESSED; | |
| 4720 | |||
| 4721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 226070 times.
|
452140 | if (col_type == DATA_POINT) { |
| 4722 | /* DATA_POINT should be of fixed length, | ||
| 4723 | instead of the pack_length(blob length). */ | ||
| 4724 | ✗ | col_len = DATA_POINT_LEN; | |
| 4725 | } | ||
| 4726 | |||
| 4727 |
2/4✓ Branch 0 taken 226070 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 226070 times.
|
452140 | if (dict_col_name_is_reserved(field->field_name)) { |
| 4728 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4729 | ✗ | my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name); | |
| 4730 | ✗ | goto new_clustered_failed; | |
| 4731 | } | ||
| 4732 | |||
| 4733 |
2/2✓ Branch 0 taken 837 times.
✓ Branch 1 taken 225233 times.
|
452140 | if (is_virtual) { |
| 4734 | 1674 | field_type |= DATA_VIRTUAL; | |
| 4735 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 835 times.
|
1674 | if (is_multi_value) { |
| 4736 | 4 | field_type |= DATA_MULTI_VALUE; | |
| 4737 | } | ||
| 4738 |
1/2✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
|
1674 | dict_mem_table_add_v_col( |
| 4739 |
1/2✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
|
1674 | ctx->new_table, ctx->heap, field->field_name, col_type, |
| 4740 | dtype_form_prtype(field_type, charset_no), col_len, i, | ||
| 4741 | 1674 | field->gcol_info->non_virtual_base_columns(), | |
| 4742 |
1/2✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
|
1674 | !field->is_hidden_by_system()); |
| 4743 | } else { | ||
| 4744 | 900932 | dict_mem_table_add_col( | |
| 4745 |
1/2✓ Branch 0 taken 225233 times.
✗ Branch 1 not taken.
|
450466 | ctx->new_table, ctx->heap, field->field_name, col_type, |
| 4746 | dtype_form_prtype(field_type, charset_no), col_len, | ||
| 4747 |
2/4✓ Branch 0 taken 225233 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 225233 times.
✗ Branch 3 not taken.
|
450466 | !field->is_hidden_by_system(), UINT32_UNDEFINED, UINT8_UNDEFINED, |
| 4748 | UINT8_UNDEFINED); | ||
| 4749 | } | ||
| 4750 | } | ||
| 4751 | |||
| 4752 |
2/2✓ Branch 0 taken 823 times.
✓ Branch 1 taken 29644 times.
|
60934 | if (n_v_cols) { |
| 4753 | 1646 | ulint z = 0; | |
| 4754 |
2/2✓ Branch 0 taken 4879 times.
✓ Branch 1 taken 823 times.
|
11404 | for (uint i = 0; i < altered_table->s->fields; i++) { |
| 4755 | dict_v_col_t *v_col; | ||
| 4756 | 9758 | const Field *field = altered_table->field[i]; | |
| 4757 | |||
| 4758 |
4/4✓ Branch 0 taken 859 times.
✓ Branch 1 taken 4020 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 837 times.
|
9758 | if (!innobase_is_v_fld(field)) { |
| 4759 | 8084 | continue; | |
| 4760 | } | ||
| 4761 |
1/2✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
|
1674 | v_col = dict_table_get_nth_v_col(ctx->new_table, z); |
| 4762 | 1674 | z++; | |
| 4763 |
1/2✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
|
1674 | innodb_base_col_setup(ctx->new_table, field, v_col); |
| 4764 | } | ||
| 4765 | } | ||
| 4766 | |||
| 4767 | /* Populate row version and column counts for new table */ | ||
| 4768 | 60934 | ctx->new_table->current_row_version = 0; | |
| 4769 | 60934 | ctx->new_table->initial_col_count = altered_table->s->fields - n_v_cols; | |
| 4770 | 60934 | ctx->new_table->current_col_count = ctx->new_table->initial_col_count; | |
| 4771 | 60934 | ctx->new_table->total_col_count = ctx->new_table->initial_col_count; | |
| 4772 | |||
| 4773 |
2/2✓ Branch 0 taken 122 times.
✓ Branch 1 taken 30345 times.
|
60934 | if (add_fts_doc_id) { |
| 4774 |
1/2✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
|
244 | fts_add_doc_id_column(ctx->new_table, ctx->heap); |
| 4775 | 244 | ctx->new_table->fts->doc_col = fts_doc_id_col; | |
| 4776 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
|
244 | ut_ad(fts_doc_id_col == altered_table->s->fields - n_v_cols); |
| 4777 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30344 times.
|
60690 | } else if (ctx->new_table->fts) { |
| 4778 | 2 | ctx->new_table->fts->doc_col = fts_doc_id_col; | |
| 4779 | } | ||
| 4780 | |||
| 4781 | const char *compression; | ||
| 4782 | |||
| 4783 | 60934 | compression = ha_alter_info->create_info->compress.str; | |
| 4784 | |||
| 4785 |
2/4✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30467 times.
|
60934 | if (Compression::validate(compression) != DB_SUCCESS) { |
| 4786 | ✗ | compression = nullptr; | |
| 4787 | } | ||
| 4788 | |||
| 4789 | const char *encrypt; | ||
| 4790 | 60934 | encrypt = ha_alter_info->create_info->encrypt_type.str; | |
| 4791 | 60934 | key_id = ha_alter_info->create_info->encryption_key_id; | |
| 4792 | |||
| 4793 | // re-encrypting, check that key used to encrypt table is present | ||
| 4794 |
2/2✓ Branch 0 taken 626 times.
✓ Branch 1 taken 29841 times.
|
60934 | if (DICT_TF2_FLAG_IS_SET(ctx->old_table, |
| 4795 | DICT_TF2_ENCRYPTION_FILE_PER_TABLE)) { | ||
| 4796 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 2 times.
|
1252 | if (Encryption::is_master_key_encryption( |
| 4797 | 1252 | old_table->s->encrypt_type.str)) { | |
| 4798 | // re-encrypting from master key encryption | ||
| 4799 | /* Check if keyring is ready. */ | ||
| 4800 | 1248 | byte *master_key = NULL; | |
| 4801 | uint32_t master_key_id; | ||
| 4802 | |||
| 4803 | 1248 | Encryption::get_master_key(&master_key_id, &master_key); | |
| 4804 | |||
| 4805 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 624 times.
|
1248 | if (master_key == NULL) { |
| 4806 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4807 | ✗ | my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0)); | |
| 4808 | ✗ | goto new_clustered_failed; | |
| 4809 | } else { | ||
| 4810 |
1/2✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
|
1248 | my_free(master_key); |
| 4811 | } | ||
| 4812 | } | ||
| 4813 | } | ||
| 4814 | |||
| 4815 |
2/2✓ Branch 0 taken 12070 times.
✓ Branch 1 taken 18397 times.
|
60934 | if (none_explicitly_specified) |
| 4816 | 24140 | mode = FIL_ENCRYPTION_OFF; | |
| 4817 | 36794 | else if (Encryption::is_keyring(encrypt) || | |
| 4818 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18397 times.
|
36794 | (srv_default_table_encryption == |
| 4819 | ✗ | DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING && | |
| 4820 | ✗ | !none_explicitly_specified && | |
| 4821 |
2/6✓ Branch 0 taken 18397 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18397 times.
|
73588 | !Encryption::is_master_key_encryption(encrypt)) || |
| 4822 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18397 times.
|
36794 | ha_alter_info->create_info->was_encryption_key_id_set) { |
| 4823 | ✗ | mode = Encryption::is_keyring(encrypt) ? FIL_ENCRYPTION_ON | |
| 4824 | : FIL_ENCRYPTION_DEFAULT; | ||
| 4825 | uint tablespace_key_version; | ||
| 4826 | byte *tablespace_key; | ||
| 4827 | |||
| 4828 | // TODO: Add checking for error returned from keyring function, not only | ||
| 4829 | // checking if tablespace is null | ||
| 4830 | ✗ | Encryption::get_latest_key_or_create( | |
| 4831 | key_id, server_uuid, &tablespace_key_version, &tablespace_key); | ||
| 4832 | ✗ | if (tablespace_key == NULL) { | |
| 4833 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4834 | ✗ | my_printf_error( | |
| 4835 | ER_ILLEGAL_HA_CREATE_OPTION, | ||
| 4836 | "Seems that keyring is down. It is not possible to encrypt table" | ||
| 4837 | " without keyring. Please install a keyring and try again.", | ||
| 4838 | MYF(0)); | ||
| 4839 | ✗ | goto new_clustered_failed; | |
| 4840 | } else { | ||
| 4841 | ✗ | my_free(tablespace_key); | |
| 4842 | } | ||
| 4843 | |||
| 4844 | ✗ | if (mode == FIL_ENCRYPTION_ON || | |
| 4845 | ✗ | (mode == FIL_ENCRYPTION_DEFAULT && | |
| 4846 | ✗ | srv_default_table_encryption == | |
| 4847 | DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING)) { | ||
| 4848 | ✗ | DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_ENCRYPTION_FILE_PER_TABLE); | |
| 4849 | } | ||
| 4850 | 78124 | } else if (!(ctx->new_table->flags2 & DICT_TF2_USE_FILE_PER_TABLE) && | |
| 4851 |
3/4✓ Branch 0 taken 2268 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 388 times.
✓ Branch 3 taken 1880 times.
|
9072 | ha_alter_info->create_info->encrypt_type.length > 0 && |
| 4852 |
3/4✓ Branch 0 taken 2268 times.
✓ Branch 1 taken 16129 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18397 times.
|
45866 | Encryption::is_master_key_encryption(encrypt) && |
| 4853 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 388 times.
|
776 | !DICT_TF2_FLAG_IS_SET(ctx->old_table, |
| 4854 | DICT_TF2_ENCRYPTION_FILE_PER_TABLE)) { | ||
| 4855 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4856 | ✗ | my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0)); | |
| 4857 | ✗ | goto new_clustered_failed; | |
| 4858 |
2/2✓ Branch 0 taken 624 times.
✓ Branch 1 taken 17773 times.
|
36794 | } else if (Encryption::is_master_key_encryption(encrypt)) { |
| 4859 | /* Set the encryption flag. */ | ||
| 4860 | |||
| 4861 | /* Check if keyring is ready. */ | ||
| 4862 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 624 times.
|
1248 | if (!Encryption::check_keyring()) { |
| 4863 | ✗ | dict_mem_table_free(ctx->new_table); | |
| 4864 | ✗ | my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0)); | |
| 4865 | ✗ | goto new_clustered_failed; | |
| 4866 | } else { | ||
| 4867 | /* This flag will be used to set encryption | ||
| 4868 | option for file-per-table tablespace. */ | ||
| 4869 | 1248 | DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_ENCRYPTION_FILE_PER_TABLE); | |
| 4870 | } | ||
| 4871 | } | ||
| 4872 | |||
| 4873 |
1/2✓ Branch 0 taken 30467 times.
✗ Branch 1 not taken.
|
60934 | dict_sys_mutex_exit(); |
| 4874 | |||
| 4875 | 60934 | keyring_encryption_key_id.was_encryption_key_id_set = | |
| 4876 | 60934 | ha_alter_info->create_info->was_encryption_key_id_set; | |
| 4877 | 60934 | keyring_encryption_key_id.id = key_id; | |
| 4878 | |||
| 4879 | 121820 | error = row_create_table_for_mysql(ctx->new_table, compression, | |
| 4880 |
1/2✓ Branch 0 taken 30443 times.
✗ Branch 1 not taken.
|
60934 | ha_alter_info->create_info, ctx->trx, nullptr, |
| 4881 | mode, keyring_encryption_key_id); | ||
| 4882 | |||
| 4883 |
1/2✓ Branch 0 taken 30443 times.
✗ Branch 1 not taken.
|
60886 | dict_sys_mutex_enter(); |
| 4884 | |||
| 4885 |
2/7✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
|
60886 | switch (error) { |
| 4886 | dict_table_t *temp_table; | ||
| 4887 | 60876 | case DB_SUCCESS: | |
| 4888 | /* To bump up the table ref count and move it | ||
| 4889 | to LRU list if it's not temporary table */ | ||
| 4890 |
2/4✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30438 times.
|
60876 | ut_ad(dict_sys_mutex_own()); |
| 4891 |
3/6✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30438 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30438 times.
✗ Branch 5 not taken.
|
121752 | if (!ctx->new_table->is_temporary() && |
| 4892 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
60876 | !ctx->new_table->explicitly_non_lru) { |
| 4893 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
60876 | dict_table_allow_eviction(ctx->new_table); |
| 4894 | } | ||
| 4895 |
2/2✓ Branch 0 taken 30315 times.
✓ Branch 1 taken 123 times.
|
60876 | if ((ctx->new_table->flags2 & |
| 4896 | 60630 | (DICT_TF2_FTS | DICT_TF2_FTS_ADD_DOC_ID)) || | |
| 4897 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30315 times.
|
60630 | ctx->new_table->fts != nullptr) { |
| 4898 |
1/2✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
|
246 | fts_freeze_aux_tables(ctx->new_table); |
| 4899 | } | ||
| 4900 | temp_table = | ||
| 4901 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
60876 | dd_table_open_on_name_in_mem(ctx->new_table->name.m_name, true); |
| 4902 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
60876 | ut_a(ctx->new_table == temp_table); |
| 4903 | /* n_ref_count must be 1, because purge cannot | ||
| 4904 | be executing on this very table as we are | ||
| 4905 | holding MDL lock. */ | ||
| 4906 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30438 times.
|
60876 | assert(ctx->new_table->get_ref_count() == 1); |
| 4907 | 60876 | break; | |
| 4908 | ✗ | case DB_TABLESPACE_EXISTS: | |
| 4909 | ✗ | my_error(ER_TABLESPACE_EXISTS, MYF(0), new_table_name); | |
| 4910 | ✗ | goto new_clustered_failed; | |
| 4911 | ✗ | case DB_DUPLICATE_KEY: | |
| 4912 | ✗ | my_error(HA_ERR_TABLE_EXIST, MYF(0), altered_table->s->table_name.str); | |
| 4913 | ✗ | goto new_clustered_failed; | |
| 4914 | ✗ | case DB_UNSUPPORTED: | |
| 4915 | ✗ | my_error(ER_UNSUPPORTED_EXTENSION, MYF(0), new_table_name); | |
| 4916 | ✗ | goto new_clustered_failed; | |
| 4917 | ✗ | case DB_IO_NO_PUNCH_HOLE_FS: | |
| 4918 | ✗ | my_error(ER_INNODB_COMPRESSION_FAILURE, MYF(0), | |
| 4919 | "Punch hole not supported by the filesystem or the tablespace " | ||
| 4920 | "page size is not large enough."); | ||
| 4921 | ✗ | goto new_clustered_failed; | |
| 4922 | ✗ | case DB_IO_NO_PUNCH_HOLE_TABLESPACE: | |
| 4923 | ✗ | my_error(ER_INNODB_COMPRESSION_FAILURE, MYF(0), | |
| 4924 | "Page Compression is not supported for this tablespace"); | ||
| 4925 | ✗ | goto new_clustered_failed; | |
| 4926 | 10 | default: | |
| 4927 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
10 | my_error_innodb(error, table_name, flags); |
| 4928 | 10 | new_clustered_failed: | |
| 4929 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
10 | ut_ad(user_table->get_ref_count() == 1); |
| 4930 | |||
| 4931 | 10 | goto err_exit; | |
| 4932 | } | ||
| 4933 | |||
| 4934 |
2/2✓ Branch 0 taken 9342 times.
✓ Branch 1 taken 21096 times.
|
60876 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN) { |
| 4935 | add_cols = | ||
| 4936 |
2/4✓ Branch 0 taken 9342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9342 times.
✗ Branch 3 not taken.
|
18684 | dtuple_create_with_vcol(ctx->heap, ctx->new_table->get_n_cols(), |
| 4937 |
1/2✓ Branch 0 taken 9342 times.
✗ Branch 1 not taken.
|
18684 | dict_table_get_n_v_cols(ctx->new_table)); |
| 4938 | |||
| 4939 |
1/2✓ Branch 0 taken 9342 times.
✗ Branch 1 not taken.
|
18684 | dict_table_copy_types(add_cols, ctx->new_table); |
| 4940 | } else { | ||
| 4941 | 42192 | add_cols = nullptr; | |
| 4942 | } | ||
| 4943 | |||
| 4944 | 121752 | ctx->col_map = innobase_build_col_map(ha_alter_info, altered_table, | |
| 4945 |
1/2✓ Branch 0 taken 30438 times.
✗ Branch 1 not taken.
|
60876 | old_table, ctx->new_table, user_table, |
| 4946 | add_cols, ctx->heap, prebuilt); | ||
| 4947 | 60876 | ctx->add_cols = add_cols; | |
| 4948 | } else { | ||
| 4949 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5291 times.
|
10582 | assert( |
| 4950 | !innobase_need_rebuild(ha_alter_info, old_table, is_file_per_table)); | ||
| 4951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5291 times.
|
10582 | assert(old_table->s->primary_key == altered_table->s->primary_key); |
| 4952 | |||
| 4953 |
3/4✓ Branch 0 taken 5291 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9630 times.
✓ Branch 3 taken 5286 times.
|
29832 | for (dict_index_t *index = user_table->first_index(); index != nullptr; |
| 4954 |
1/2✓ Branch 0 taken 9625 times.
✗ Branch 1 not taken.
|
19250 | index = index->next()) { |
| 4955 |
7/8✓ Branch 0 taken 9399 times.
✓ Branch 1 taken 231 times.
✓ Branch 2 taken 9399 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 9394 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 9625 times.
|
19260 | if (!index->to_be_dropped && index->is_corrupted()) { |
| 4956 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
10 | my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0)); |
| 4957 | 10 | goto error_handled; | |
| 4958 | } | ||
| 4959 | } | ||
| 4960 | |||
| 4961 |
6/6✓ Branch 0 taken 4951 times.
✓ Branch 1 taken 335 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 4922 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 5257 times.
|
10572 | if (!ctx->new_table->fts && innobase_fulltext_exist(altered_table)) { |
| 4962 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
58 | ctx->new_table->fts = fts_create(ctx->new_table); |
| 4963 | 58 | ctx->new_table->fts->doc_col = fts_doc_id_col; | |
| 4964 | } | ||
| 4965 | |||
| 4966 | /* Check if we need to update mtypes of legacy GIS columns. | ||
| 4967 | This check is only needed when we don't have to rebuild | ||
| 4968 | the table, since rebuild would update all mtypes for GIS | ||
| 4969 | columns */ | ||
| 4970 |
1/2✓ Branch 0 taken 5286 times.
✗ Branch 1 not taken.
|
10572 | error = innobase_check_gis_columns(ha_alter_info, ctx->new_table); |
| 4971 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5286 times.
|
10572 | if (error != DB_SUCCESS) { |
| 4972 | ✗ | ut_ad(error == DB_ERROR); | |
| 4973 | ✗ | error = DB_UNSUPPORTED; | |
| 4974 | ✗ | goto error_handling; | |
| 4975 | } | ||
| 4976 | } | ||
| 4977 | |||
| 4978 |
2/4✓ Branch 0 taken 35724 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35724 times.
|
71448 | ut_ad(!dict_table_is_compressed_temporary(ctx->new_table)); |
| 4979 | |||
| 4980 | /* Assign table_id, so that no table id of | ||
| 4981 | fts_create_index_tables() will be written to the undo logs. */ | ||
| 4982 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35724 times.
|
71448 | assert(ctx->new_table->id != 0); |
| 4983 | |||
| 4984 | /* Create the indexes and load into dictionary. */ | ||
| 4985 | |||
| 4986 |
2/2✓ Branch 0 taken 45473 times.
✓ Branch 1 taken 35583 times.
|
162112 | for (ulint a = 0; a < ctx->num_to_add_index; a++) { |
| 4987 |
2/2✓ Branch 0 taken 317 times.
✓ Branch 1 taken 45156 times.
|
90946 | if (index_defs[a].m_ind_type & DICT_VIRTUAL && |
| 4988 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 309 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
634 | ha_alter_info->virtual_column_drop_count > 0 && !new_clustered) { |
| 4989 | 16 | innodb_v_adjust_idx_col(ha_alter_info, old_table, | |
| 4990 | 16 | ha_alter_info->virtual_column_drop_count, | |
| 4991 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
16 | &index_defs[a]); |
| 4992 | } | ||
| 4993 | |||
| 4994 | 181664 | ctx->add_index[a] = | |
| 4995 | 90946 | ddl::create_index(ctx->trx, ctx->new_table, &index_defs[a], add_v); | |
| 4996 | |||
| 4997 | 90718 | add_key_nums[a] = index_defs[a].m_key_number; | |
| 4998 | |||
| 4999 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 45333 times.
|
90718 | if (!ctx->add_index[a]) { |
| 5000 | 52 | error = ctx->trx->error_state; | |
| 5001 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
52 | assert(error != DB_SUCCESS); |
| 5002 | 52 | goto error_handling; | |
| 5003 | } | ||
| 5004 | |||
| 5005 |
2/4✓ Branch 0 taken 45333 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 45333 times.
|
90666 | assert(ctx->add_index[a]->is_committed() == new_clustered); |
| 5006 | |||
| 5007 |
2/2✓ Branch 0 taken 459 times.
✓ Branch 1 taken 44874 times.
|
90666 | if (ctx->add_index[a]->type & DICT_FTS) { |
| 5008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
|
918 | assert(num_fts_index); |
| 5009 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
|
918 | assert(!fts_index); |
| 5010 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
|
918 | assert(ctx->add_index[a]->type == DICT_FTS); |
| 5011 | 918 | fts_index = ctx->add_index[a]; | |
| 5012 | } | ||
| 5013 | |||
| 5014 | /* If only online ALTER TABLE operations have been | ||
| 5015 | requested, allocate a modification log. If the table | ||
| 5016 | will be locked anyway, the modification | ||
| 5017 | log is unnecessary. When rebuilding the table | ||
| 5018 | (new_clustered), we will allocate the log for the | ||
| 5019 | clustered index of the old table, later. */ | ||
| 5020 |
9/10✓ Branch 0 taken 5439 times.
✓ Branch 1 taken 39894 times.
✓ Branch 2 taken 4827 times.
✓ Branch 3 taken 612 times.
✓ Branch 4 taken 4823 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4823 times.
✓ Branch 8 taken 40510 times.
✓ Branch 9 taken 4823 times.
|
100312 | if (new_clustered || !ctx->online || user_table->ibd_file_missing || |
| 5021 | 9646 | dict_table_is_discarded(user_table)) { | |
| 5022 | /* No need to allocate a modification log. */ | ||
| 5023 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40510 times.
|
81020 | ut_ad(!ctx->add_index[a]->online_log); |
| 5024 |
1/2✓ Branch 0 taken 4823 times.
✗ Branch 1 not taken.
|
9646 | } else if (ctx->add_index[a]->type & DICT_FTS) { |
| 5025 | /* Fulltext indexes are not covered | ||
| 5026 | by a modification log. */ | ||
| 5027 | } else { | ||
| 5028 |
3/4✓ Branch 0 taken 4823 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4822 times.
|
9646 | DBUG_EXECUTE_IF("innodb_OOM_prepare_inplace_alter", |
| 5029 | error = DB_OUT_OF_MEMORY; | ||
| 5030 | goto error_handling;); | ||
| 5031 |
1/2✓ Branch 0 taken 4822 times.
✗ Branch 1 not taken.
|
9644 | rw_lock_x_lock(&ctx->add_index[a]->lock, UT_LOCATION_HERE); |
| 5032 |
1/2✓ Branch 0 taken 4822 times.
✗ Branch 1 not taken.
|
9644 | bool ok = row_log_allocate(ctx->add_index[a], nullptr, true, nullptr, |
| 5033 | nullptr, path); | ||
| 5034 |
1/2✓ Branch 0 taken 4822 times.
✗ Branch 1 not taken.
|
9644 | rw_lock_x_unlock(&ctx->add_index[a]->lock); |
| 5035 | |||
| 5036 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4822 times.
|
9644 | if (!ok) { |
| 5037 | ✗ | error = DB_OUT_OF_MEMORY; | |
| 5038 | ✗ | goto error_handling; | |
| 5039 | } | ||
| 5040 | } | ||
| 5041 | } | ||
| 5042 | |||
| 5043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35583 times.
|
71166 | ut_ad(new_clustered == ctx->need_rebuild()); |
| 5044 | |||
| 5045 |
3/4✓ Branch 0 taken 35583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 35582 times.
|
71166 | DBUG_EXECUTE_IF("innodb_OOM_prepare_inplace_alter", error = DB_OUT_OF_MEMORY; |
| 5046 | goto error_handling;); | ||
| 5047 | |||
| 5048 |
2/2✓ Branch 0 taken 30364 times.
✓ Branch 1 taken 5218 times.
|
71164 | if (new_clustered) { |
| 5049 |
1/2✓ Branch 0 taken 30364 times.
✗ Branch 1 not taken.
|
60728 | dict_index_t *clust_index = user_table->first_index(); |
| 5050 |
1/2✓ Branch 0 taken 30364 times.
✗ Branch 1 not taken.
|
60728 | dict_index_t *new_clust_index = ctx->new_table->first_index(); |
| 5051 | 60728 | ctx->skip_pk_sort = | |
| 5052 |
1/2✓ Branch 0 taken 30364 times.
✗ Branch 1 not taken.
|
60728 | innobase_pk_order_preserved(ctx->col_map, clust_index, new_clust_index); |
| 5053 | |||
| 5054 |
4/6✓ Branch 0 taken 30364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 30320 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
|
60728 | DBUG_EXECUTE_IF("innodb_alter_table_pk_assert_no_sort", |
| 5055 | assert(ctx->skip_pk_sort);); | ||
| 5056 | |||
| 5057 |
2/2✓ Branch 0 taken 30072 times.
✓ Branch 1 taken 292 times.
|
60728 | if (ctx->online) { |
| 5058 | /* Allocate a log for online table rebuild. */ | ||
| 5059 |
1/2✓ Branch 0 taken 30072 times.
✗ Branch 1 not taken.
|
60144 | rw_lock_x_lock(&clust_index->lock, UT_LOCATION_HERE); |
| 5060 | 120288 | bool ok = row_log_allocate( | |
| 5061 | clust_index, ctx->new_table, | ||
| 5062 |
1/2✓ Branch 0 taken 30072 times.
✗ Branch 1 not taken.
|
60144 | !(ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX), |
| 5063 | ctx->add_cols, ctx->col_map, path); | ||
| 5064 |
1/2✓ Branch 0 taken 30072 times.
✗ Branch 1 not taken.
|
60144 | rw_lock_x_unlock(&clust_index->lock); |
| 5065 | |||
| 5066 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30072 times.
|
60144 | if (!ok) { |
| 5067 | ✗ | error = DB_OUT_OF_MEMORY; | |
| 5068 | ✗ | goto error_handling; | |
| 5069 | } | ||
| 5070 | } | ||
| 5071 | } | ||
| 5072 | |||
| 5073 |
2/2✓ Branch 0 taken 34699 times.
✓ Branch 1 taken 883 times.
|
71164 | if (ctx->online) { |
| 5074 | /* Assign a consistent read view for the index build scan. */ | ||
| 5075 |
1/2✓ Branch 0 taken 34699 times.
✗ Branch 1 not taken.
|
69398 | trx_assign_read_view(ctx->prebuilt->trx); |
| 5076 | } | ||
| 5077 | |||
| 5078 |
2/2✓ Branch 0 taken 459 times.
✓ Branch 1 taken 35123 times.
|
71164 | if (fts_index) { |
| 5079 | /* Ensure that the dictionary operation mode will | ||
| 5080 | not change while creating the auxiliary tables. */ | ||
| 5081 | #ifdef UNIV_DEBUG | ||
| 5082 |
1/2✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
|
918 | trx_dict_op_t op = trx_get_dict_operation(ctx->trx); |
| 5083 | #endif | ||
| 5084 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
|
918 | ut_ad(ctx->trx->dict_operation_lock_mode == RW_X_LATCH); |
| 5085 |
2/4✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 459 times.
|
918 | ut_ad(dict_sys_mutex_own()); |
| 5086 |
2/4✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 459 times.
|
918 | ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); |
| 5087 | |||
| 5088 | 918 | DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); | |
| 5089 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 336 times.
|
918 | if (new_clustered) { |
| 5090 | /* For !new_clustered, this will be set at | ||
| 5091 | commit_cache_norebuild(). */ | ||
| 5092 | 492 | ctx->new_table->fts_doc_id_index = | |
| 5093 |
1/2✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
|
246 | dict_table_get_index_on_name(ctx->new_table, FTS_DOC_ID_INDEX_NAME); |
| 5094 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
246 | assert(ctx->new_table->fts_doc_id_index != nullptr); |
| 5095 | } | ||
| 5096 | |||
| 5097 | /* This function will commit the transaction and reset | ||
| 5098 | the trx_t::dict_operation flag on success. */ | ||
| 5099 | |||
| 5100 |
1/2✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
|
918 | dict_sys_mutex_exit(); |
| 5101 |
1/2✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
|
918 | error = fts_create_index_tables(ctx->trx, fts_index); |
| 5102 |
1/2✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
|
918 | dict_sys_mutex_enter(); |
| 5103 | |||
| 5104 |
2/4✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 459 times.
|
918 | DBUG_EXECUTE_IF("innodb_test_fail_after_fts_index_table", |
| 5105 | error = DB_LOCK_WAIT_TIMEOUT; | ||
| 5106 | goto error_handling;); | ||
| 5107 | |||
| 5108 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 455 times.
|
918 | if (error != DB_SUCCESS) { |
| 5109 | 8 | goto error_handling; | |
| 5110 | } | ||
| 5111 | |||
| 5112 |
5/6✓ Branch 0 taken 455 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 265 times.
✓ Branch 4 taken 190 times.
✓ Branch 5 taken 265 times.
|
1820 | if (!ctx->new_table->fts || |
| 5113 | 910 | ib_vector_size(ctx->new_table->fts->indexes) == 0) { | |
| 5114 | bool exist_fts_common; | ||
| 5115 | |||
| 5116 |
1/2✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
|
380 | dict_sys_mutex_exit(); |
| 5117 |
1/2✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
|
380 | exist_fts_common = fts_check_common_tables_exist(ctx->new_table); |
| 5118 | |||
| 5119 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 40 times.
|
380 | if (!exist_fts_common) { |
| 5120 | 600 | error = fts_create_common_tables(ctx->trx, ctx->new_table, | |
| 5121 |
1/2✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
|
300 | user_table->name.m_name, true); |
| 5122 | |||
| 5123 |
2/4✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 150 times.
|
300 | DBUG_EXECUTE_IF("innodb_test_fail_after_fts_common_table", |
| 5124 | error = DB_LOCK_WAIT_TIMEOUT;); | ||
| 5125 | |||
| 5126 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 148 times.
|
300 | if (error != DB_SUCCESS) { |
| 5127 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | dict_sys_mutex_enter(); |
| 5128 | 4 | goto error_handling; | |
| 5129 | } | ||
| 5130 | |||
| 5131 | 296 | build_fts_common = true; | |
| 5132 | } | ||
| 5133 | |||
| 5134 | 1128 | error = innobase_fts_load_stopword(ctx->new_table, nullptr, | |
| 5135 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | ctx->prebuilt->trx->mysql_thd) |
| 5136 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | ? DB_SUCCESS |
| 5137 | : DB_ERROR; | ||
| 5138 | |||
| 5139 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | dict_sys_mutex_enter(); |
| 5140 | |||
| 5141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
|
376 | if (error != DB_SUCCESS) { |
| 5142 | ✗ | goto error_handling; | |
| 5143 | } | ||
| 5144 | } | ||
| 5145 | |||
| 5146 |
2/4✓ Branch 0 taken 453 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 453 times.
|
906 | ut_ad(trx_get_dict_operation(ctx->trx) == op); |
| 5147 | } | ||
| 5148 | |||
| 5149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35576 times.
|
71152 | assert(error == DB_SUCCESS); |
| 5150 | |||
| 5151 |
4/4✓ Branch 0 taken 35428 times.
✓ Branch 1 taken 148 times.
✓ Branch 2 taken 305 times.
✓ Branch 3 taken 35123 times.
|
71152 | if (build_fts_common || fts_index) { |
| 5152 |
1/2✓ Branch 0 taken 453 times.
✗ Branch 1 not taken.
|
906 | fts_freeze_aux_tables(ctx->new_table); |
| 5153 | } | ||
| 5154 | |||
| 5155 |
1/2✓ Branch 0 taken 35576 times.
✗ Branch 1 not taken.
|
71152 | row_mysql_unlock_data_dictionary(ctx->prebuilt->trx); |
| 5156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35576 times.
|
71152 | ut_ad(ctx->trx == ctx->prebuilt->trx); |
| 5157 | 71152 | dict_locked = false; | |
| 5158 | |||
| 5159 |
2/4✓ Branch 0 taken 35576 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35576 times.
|
71152 | if (dd_prepare_inplace_alter_table(ctx->prebuilt->trx->mysql_thd, user_table, |
| 5160 | ctx->new_table, old_dd_tab)) { | ||
| 5161 | ✗ | error = DB_ERROR; | |
| 5162 | } | ||
| 5163 | |||
| 5164 |
1/2✓ Branch 0 taken 35576 times.
✗ Branch 1 not taken.
|
71152 | if (error == DB_SUCCESS) { |
| 5165 |
2/2✓ Branch 0 taken 148 times.
✓ Branch 1 taken 35428 times.
|
71152 | if (build_fts_common) { |
| 5166 |
2/4✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
|
296 | if (!fts_create_common_dd_tables(ctx->new_table)) { |
| 5167 | ✗ | error = DB_ERROR; | |
| 5168 | ✗ | goto error_handling; | |
| 5169 | } | ||
| 5170 | } | ||
| 5171 | |||
| 5172 |
2/2✓ Branch 0 taken 453 times.
✓ Branch 1 taken 35123 times.
|
71152 | if (fts_index) { |
| 5173 |
1/2✓ Branch 0 taken 453 times.
✗ Branch 1 not taken.
|
906 | error = fts_create_index_dd_tables(ctx->new_table); |
| 5174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 453 times.
|
906 | if (error != DB_SUCCESS) { |
| 5175 | ✗ | goto error_handling; | |
| 5176 | } | ||
| 5177 | } | ||
| 5178 | } | ||
| 5179 | |||
| 5180 |
4/6✓ Branch 0 taken 35576 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 35575 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
71152 | DBUG_EXECUTE_IF("crash_innodb_add_index_after", DBUG_SUICIDE();); |
| 5181 | |||
| 5182 | 71150 | error_handling: | |
| 5183 | |||
| 5184 |
4/4✓ Branch 0 taken 35461 times.
✓ Branch 1 taken 148 times.
✓ Branch 2 taken 311 times.
✓ Branch 3 taken 35150 times.
|
71218 | if (build_fts_common || fts_index) { |
| 5185 |
1/2✓ Branch 0 taken 459 times.
✗ Branch 1 not taken.
|
918 | fts_detach_aux_tables(ctx->new_table, dict_locked); |
| 5186 | } | ||
| 5187 | |||
| 5188 | /* After an error, remove all those index definitions from the | ||
| 5189 | dictionary which were defined. */ | ||
| 5190 | |||
| 5191 |
2/5✓ Branch 0 taken 35575 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
|
71218 | switch (error) { |
| 5192 | 71150 | case DB_SUCCESS: | |
| 5193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35575 times.
|
71150 | ut_a(!dict_locked); |
| 5194 | |||
| 5195 |
1/2✓ Branch 0 taken 35575 times.
✗ Branch 1 not taken.
|
71150 | ut_d(dict_sys_mutex_enter()); |
| 5196 |
1/2✓ Branch 0 taken 35575 times.
✗ Branch 1 not taken.
|
71150 | ut_d(dict_table_check_for_dup_indexes(user_table, CHECK_PARTIAL_OK)); |
| 5197 |
1/2✓ Branch 0 taken 35575 times.
✗ Branch 1 not taken.
|
71150 | ut_d(dict_sys_mutex_exit()); |
| 5198 | 71150 | return false; | |
| 5199 | ✗ | case DB_TABLESPACE_EXISTS: | |
| 5200 | ✗ | my_error(ER_TABLESPACE_EXISTS, MYF(0), "(unknown)"); | |
| 5201 | ✗ | break; | |
| 5202 | ✗ | case DB_DUPLICATE_KEY: | |
| 5203 | ✗ | my_error(ER_DUP_KEY, MYF(0)); | |
| 5204 | ✗ | break; | |
| 5205 | ✗ | case DB_UNSUPPORTED: | |
| 5206 | ✗ | my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0)); | |
| 5207 | ✗ | break; | |
| 5208 | 68 | default: | |
| 5209 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
68 | my_error_innodb(error, table_name, user_table->flags); |
| 5210 | } | ||
| 5211 | |||
| 5212 | 82 | error_handled: | |
| 5213 | |||
| 5214 | 82 | ctx->prebuilt->trx->error_index = nullptr; | |
| 5215 | 82 | ctx->trx->error_state = DB_SUCCESS; | |
| 5216 | |||
| 5217 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 39 times.
|
82 | if (!dict_locked) { |
| 5218 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | row_mysql_lock_data_dictionary(ctx->prebuilt->trx, UT_LOCATION_HERE); |
| 5219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
4 | ut_ad(ctx->trx == ctx->prebuilt->trx); |
| 5220 | } | ||
| 5221 | |||
| 5222 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 32 times.
|
82 | if (new_clustered) { |
| 5223 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | if (ctx->need_rebuild()) { |
| 5224 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
|
18 | if (DICT_TF2_FLAG_IS_SET(ctx->new_table, DICT_TF2_FTS)) { |
| 5225 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | innobase_drop_fts_index_table(ctx->new_table, ctx->trx); |
| 5226 | } | ||
| 5227 | |||
| 5228 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | dict_table_close_and_drop(ctx->trx, ctx->new_table); |
| 5229 | |||
| 5230 | /* Free the log for online table rebuild, if | ||
| 5231 | one was allocated. */ | ||
| 5232 | |||
| 5233 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | dict_index_t *clust_index = user_table->first_index(); |
| 5234 | |||
| 5235 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | rw_lock_x_lock(&clust_index->lock, UT_LOCATION_HERE); |
| 5236 | |||
| 5237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
18 | if (clust_index->online_log) { |
| 5238 | ✗ | ut_ad(ctx->online); | |
| 5239 | ✗ | row_log_free(clust_index->online_log); | |
| 5240 | ✗ | clust_index->online_status = ONLINE_INDEX_COMPLETE; | |
| 5241 | } | ||
| 5242 | |||
| 5243 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | rw_lock_x_unlock(&clust_index->lock); |
| 5244 | } | ||
| 5245 | |||
| 5246 | /* n_ref_count must be 1, because purge cannot | ||
| 5247 | be executing on this very table as we are | ||
| 5248 | holding MDL. */ | ||
| 5249 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
18 | assert(user_table->get_ref_count() == 1 || ctx->online); |
| 5250 | } else { | ||
| 5251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
64 | ut_ad(!ctx->need_rebuild()); |
| 5252 | 64 | ddl::drop_indexes(ctx->trx, user_table, true); | |
| 5253 | } | ||
| 5254 | |||
| 5255 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
82 | ut_d(dict_table_check_for_dup_indexes(user_table, CHECK_ALL_COMPLETE)); |
| 5256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
82 | ut_ad(!user_table->drop_aborted); |
| 5257 | |||
| 5258 | 82 | err_exit: | |
| 5259 | #ifdef UNIV_DEBUG | ||
| 5260 | /* Clear the to_be_dropped flag in the data dictionary cache. */ | ||
| 5261 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
|
96 | for (ulint i = 0; i < ctx->num_to_drop_index; i++) { |
| 5262 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | assert(ctx->drop_index[i]->is_committed()); |
| 5263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
4 | assert(ctx->drop_index[i]->to_be_dropped); |
| 5264 | 4 | ctx->drop_index[i]->to_be_dropped = 0; | |
| 5265 | } | ||
| 5266 | #endif /* UNIV_DEBUG */ | ||
| 5267 | |||
| 5268 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
92 | row_mysql_unlock_data_dictionary(ctx->prebuilt->trx); |
| 5269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
92 | ut_ad(ctx->trx == ctx->prebuilt->trx); |
| 5270 | |||
| 5271 | 92 | destroy(ctx); | |
| 5272 | 92 | ha_alter_info->handler_ctx = nullptr; | |
| 5273 | |||
| 5274 | 92 | return true; | |
| 5275 | 71246 | } | |
| 5276 | |||
| 5277 | /* Check whether an index is needed for the foreign key constraint. | ||
| 5278 | If so, if it is dropped, is there an equivalent index can play its role. | ||
| 5279 | @return true if the index is needed and can't be dropped */ | ||
| 5280 | 1992 | [[nodiscard]] static bool innobase_check_foreign_key_index( | |
| 5281 | Alter_inplace_info *ha_alter_info, /*!< in: Structure describing | ||
| 5282 | changes to be done by ALTER | ||
| 5283 | TABLE */ | ||
| 5284 | dict_index_t *index, /*!< in: index to check */ | ||
| 5285 | dict_table_t *indexed_table, /*!< in: table that owns the | ||
| 5286 | foreign keys */ | ||
| 5287 | const char **col_names, /*!< in: column names, or NULL | ||
| 5288 | for indexed_table->col_names */ | ||
| 5289 | trx_t *trx, /*!< in/out: transaction */ | ||
| 5290 | dict_foreign_t **drop_fk, /*!< in: Foreign key constraints | ||
| 5291 | to drop */ | ||
| 5292 | ulint n_drop_fk) /*!< in: Number of foreign keys | ||
| 5293 | to drop */ | ||
| 5294 | { | ||
| 5295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1992 times.
|
1992 | ut_ad(index != nullptr); |
| 5296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1992 times.
|
1992 | ut_ad(indexed_table != nullptr); |
| 5297 | |||
| 5298 | 1992 | const dict_foreign_set *fks = &indexed_table->referenced_set; | |
| 5299 | |||
| 5300 | /* Check for all FK references from other tables to the index. */ | ||
| 5301 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1992 times.
|
2015 | for (dict_foreign_set::const_iterator it = fks->begin(); it != fks->end(); |
| 5302 | 23 | ++it) { | |
| 5303 | 23 | dict_foreign_t *foreign = *it; | |
| 5304 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (foreign->referenced_index != index) { |
| 5305 | 23 | continue; | |
| 5306 | } | ||
| 5307 | ✗ | ut_ad(indexed_table == foreign->referenced_table); | |
| 5308 | |||
| 5309 | ✗ | if (nullptr == dict_foreign_find_index(indexed_table, col_names, | |
| 5310 | foreign->referenced_col_names, | ||
| 5311 | ✗ | foreign->n_fields, index, | |
| 5312 | /*check_charsets=*/true, | ||
| 5313 | ✗ | /*check_null=*/false) && | |
| 5314 | ✗ | nullptr == innobase_find_equiv_index(foreign->referenced_col_names, | |
| 5315 | ✗ | foreign->n_fields, | |
| 5316 | ✗ | ha_alter_info->key_info_buffer, | |
| 5317 | ✗ | ha_alter_info->index_add_buffer, | |
| 5318 | ha_alter_info->index_add_count)) { | ||
| 5319 | /* Index cannot be dropped. */ | ||
| 5320 | ✗ | trx->error_index = index; | |
| 5321 | ✗ | return (true); | |
| 5322 | } | ||
| 5323 | } | ||
| 5324 | |||
| 5325 | 1992 | fks = &indexed_table->foreign_set; | |
| 5326 | |||
| 5327 | /* Check for all FK references in current table using the index. */ | ||
| 5328 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1992 times.
|
2022 | for (dict_foreign_set::const_iterator it = fks->begin(); it != fks->end(); |
| 5329 | 30 | ++it) { | |
| 5330 | 30 | dict_foreign_t *foreign = *it; | |
| 5331 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 14 times.
|
30 | if (foreign->foreign_index != index) { |
| 5332 | 16 | continue; | |
| 5333 | } | ||
| 5334 | |||
| 5335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | ut_ad(indexed_table == foreign->foreign_table); |
| 5336 | |||
| 5337 | 14 | if (!innobase_dropping_foreign(foreign, drop_fk, n_drop_fk) && | |
| 5338 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | nullptr == dict_foreign_find_index(indexed_table, col_names, |
| 5339 | foreign->foreign_col_names, | ||
| 5340 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | foreign->n_fields, index, |
| 5341 | /*check_charsets=*/true, | ||
| 5342 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
26 | /*check_null=*/false) && |
| 5343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | nullptr == innobase_find_equiv_index(foreign->foreign_col_names, |
| 5344 | 11 | foreign->n_fields, | |
| 5345 | 11 | ha_alter_info->key_info_buffer, | |
| 5346 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | ha_alter_info->index_add_buffer, |
| 5347 | ha_alter_info->index_add_count)) { | ||
| 5348 | /* Index cannot be dropped. */ | ||
| 5349 | ✗ | trx->error_index = index; | |
| 5350 | ✗ | return (true); | |
| 5351 | } | ||
| 5352 | } | ||
| 5353 | |||
| 5354 | 1992 | return (false); | |
| 5355 | } | ||
| 5356 | |||
| 5357 | /** Rename a given index in the InnoDB data dictionary cache. | ||
| 5358 | @param[in,out] index index to rename | ||
| 5359 | @param new_name new index name */ | ||
| 5360 | 78 | static void rename_index_in_cache(dict_index_t *index, const char *new_name) { | |
| 5361 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | DBUG_TRACE; |
| 5362 | |||
| 5363 |
2/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
|
78 | ut_ad(dict_sys_mutex_own()); |
| 5364 |
2/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
|
78 | ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); |
| 5365 | |||
| 5366 | 78 | size_t old_name_len = strlen(index->name); | |
| 5367 | 78 | size_t new_name_len = strlen(new_name); | |
| 5368 | |||
| 5369 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 46 times.
|
78 | if (old_name_len >= new_name_len) { |
| 5370 | /* reuse the old buffer for the name if it is large enough */ | ||
| 5371 | 32 | memcpy(const_cast<char *>(index->name()), new_name, new_name_len + 1); | |
| 5372 | } else { | ||
| 5373 | /* Free the old chunk of memory if it is at the topmost | ||
| 5374 | place in the heap, otherwise the old chunk will be freed | ||
| 5375 | when the index is evicted from the cache. This code will | ||
| 5376 | kick-in in a repeated ALTER sequences where the old name is | ||
| 5377 | alternately longer/shorter than the new name: | ||
| 5378 | 1. ALTER TABLE t RENAME INDEX a TO aa; | ||
| 5379 | 2. ALTER TABLE t RENAME INDEX aa TO a; | ||
| 5380 | 3. go to 1. */ | ||
| 5381 | index->name = | ||
| 5382 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | mem_heap_strdup_replace(index->heap, |
| 5383 | /* Presumed topmost element of the heap: */ | ||
| 5384 | 46 | index->name, old_name_len + 1, new_name); | |
| 5385 | } | ||
| 5386 | 78 | } | |
| 5387 | |||
| 5388 | /** | ||
| 5389 | Rename all indexes in data dictionary cache of a given table that are | ||
| 5390 | specified in ha_alter_info. | ||
| 5391 | |||
| 5392 | @param ctx alter context, used to fetch the list of indexes to rename | ||
| 5393 | @param ha_alter_info fetch the new names from here | ||
| 5394 | */ | ||
| 5395 | 17016 | static void rename_indexes_in_cache(const ha_innobase_inplace_ctx *ctx, | |
| 5396 | const Alter_inplace_info *ha_alter_info) { | ||
| 5397 |
1/2✓ Branch 0 taken 17016 times.
✗ Branch 1 not taken.
|
17016 | DBUG_TRACE; |
| 5398 | |||
| 5399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17016 times.
|
17016 | ut_ad(ctx->num_to_rename == ha_alter_info->index_rename_count); |
| 5400 | |||
| 5401 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 17016 times.
|
17094 | for (ulint i = 0; i < ctx->num_to_rename; i++) { |
| 5402 | 78 | KEY_PAIR *pair = &ha_alter_info->index_rename_buffer[i]; | |
| 5403 | dict_index_t *index; | ||
| 5404 | |||
| 5405 | 78 | index = ctx->rename[i]; | |
| 5406 | |||
| 5407 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | ut_ad(strcmp(index->name, pair->old_key->name) == 0); |
| 5408 | |||
| 5409 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | rename_index_in_cache(index, pair->new_key->name); |
| 5410 | } | ||
| 5411 | 17016 | } | |
| 5412 | |||
| 5413 | /** Fill the stored column information in s_cols list. | ||
| 5414 | @param[in] altered_table mysql table object | ||
| 5415 | @param[in] table innodb table object | ||
| 5416 | @param[out] s_cols list of stored column | ||
| 5417 | @param[out] s_heap heap for storing stored | ||
| 5418 | column information. */ | ||
| 5419 | 94 | static void alter_fill_stored_column(const TABLE *altered_table, | |
| 5420 | dict_table_t *table, | ||
| 5421 | dict_s_col_list **s_cols, | ||
| 5422 | mem_heap_t **s_heap) { | ||
| 5423 | 94 | ulint n_cols = altered_table->s->fields; | |
| 5424 | 94 | ulint stored_col_no = 0; | |
| 5425 | |||
| 5426 |
2/2✓ Branch 0 taken 287 times.
✓ Branch 1 taken 94 times.
|
381 | for (ulint i = 0; i < n_cols; i++) { |
| 5427 | 287 | Field *field = altered_table->field[i]; | |
| 5428 | dict_s_col_t s_col; | ||
| 5429 | |||
| 5430 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 10 times.
|
287 | if (!innobase_is_v_fld(field)) { |
| 5431 | 277 | stored_col_no++; | |
| 5432 | } | ||
| 5433 | |||
| 5434 |
2/2✓ Branch 0 taken 283 times.
✓ Branch 1 taken 4 times.
|
287 | if (!innobase_is_s_fld(field)) { |
| 5435 | 283 | continue; | |
| 5436 | } | ||
| 5437 | |||
| 5438 | 4 | ulint num_base = field->gcol_info->non_virtual_base_columns(); | |
| 5439 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | dict_col_t *col = table->get_col(stored_col_no); |
| 5440 | |||
| 5441 | 4 | s_col.m_col = col; | |
| 5442 | 4 | s_col.s_pos = i; | |
| 5443 | |||
| 5444 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (*s_cols == nullptr) { |
| 5445 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | *s_cols = ut::new_withkey<dict_s_col_list>(UT_NEW_THIS_FILE_PSI_KEY); |
| 5446 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | *s_heap = mem_heap_create(100, UT_LOCATION_HERE); |
| 5447 | } | ||
| 5448 | |||
| 5449 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (num_base != 0) { |
| 5450 | 1 | s_col.base_col = static_cast<dict_col_t **>( | |
| 5451 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | mem_heap_zalloc(*s_heap, num_base * sizeof(dict_col_t))); |
| 5452 | } else { | ||
| 5453 | 3 | s_col.base_col = nullptr; | |
| 5454 | } | ||
| 5455 | |||
| 5456 | 4 | s_col.num_base = num_base; | |
| 5457 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | innodb_base_col_setup_for_stored(table, field, &s_col); |
| 5458 | |||
| 5459 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | (*s_cols)->push_back(s_col); |
| 5460 | } | ||
| 5461 | 94 | } | |
| 5462 | |||
| 5463 | template <typename Table> | ||
| 5464 | 32 | void static adjust_row_format(TABLE *old_table, TABLE *altered_table, | |
| 5465 | const Table *old_dd_tab, Table *new_dd_tab) { | ||
| 5466 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
32 | ut_ad(old_table->s->row_type == ROW_TYPE_DEFAULT || |
| 5467 | old_table->s->row_type == ROW_TYPE_COMPRESSED); | ||
| 5468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
32 | ut_ad(old_table->s->row_type == altered_table->s->row_type); |
| 5469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
32 | ut_ad(old_table->s->real_row_type != altered_table->s->real_row_type); |
| 5470 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
32 | ut_ad(old_dd_tab->table().row_format() != new_dd_tab->table().row_format()); |
| 5471 | |||
| 5472 | /* Revert the row_format in DD for altered table */ | ||
| 5473 | 32 | new_dd_tab->table().set_row_format(old_dd_tab->table().row_format()); | |
| 5474 | |||
| 5475 | /* Revert the real_row_format in table share for altered table */ | ||
| 5476 |
3/5✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
32 | switch (old_dd_tab->table().row_format()) { |
| 5477 | 24 | case dd::Table::RF_REDUNDANT: | |
| 5478 | 24 | altered_table->s->real_row_type = ROW_TYPE_REDUNDANT; | |
| 5479 | 24 | break; | |
| 5480 | 6 | case dd::Table::RF_COMPACT: | |
| 5481 | 6 | altered_table->s->real_row_type = ROW_TYPE_COMPACT; | |
| 5482 | 6 | break; | |
| 5483 | 2 | case dd::Table::RF_COMPRESSED: | |
| 5484 | 2 | altered_table->s->real_row_type = ROW_TYPE_COMPRESSED; | |
| 5485 | 2 | break; | |
| 5486 | ✗ | case dd::Table::RF_DYNAMIC: | |
| 5487 | ✗ | altered_table->s->real_row_type = ROW_TYPE_DYNAMIC; | |
| 5488 | ✗ | break; | |
| 5489 | ✗ | default: | |
| 5490 | ✗ | ut_d(ut_error); | |
| 5491 | } | ||
| 5492 | } | ||
| 5493 | |||
| 5494 | /** Implementation of prepare_inplace_alter_table() | ||
| 5495 | @tparam Table dd::Table or dd::Partition | ||
| 5496 | @param[in] altered_table TABLE object for new version of table. | ||
| 5497 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 5498 | by ALTER TABLE and holding data used | ||
| 5499 | during in-place alter. | ||
| 5500 | @param[in] old_dd_tab dd::Table object representing old | ||
| 5501 | version of the table | ||
| 5502 | @param[in,out] new_dd_tab dd::Table object representing new | ||
| 5503 | version of the table | ||
| 5504 | @retval true Failure | ||
| 5505 | @retval false Success */ | ||
| 5506 | template <typename Table> | ||
| 5507 | 113006 | bool ha_innobase::prepare_inplace_alter_table_impl( | |
| 5508 | TABLE *altered_table, Alter_inplace_info *ha_alter_info, | ||
| 5509 | const Table *old_dd_tab, Table *new_dd_tab) { | ||
| 5510 | 113006 | dict_index_t **drop_index = nullptr; /*!< Index to be dropped */ | |
| 5511 | ulint n_drop_index; /*!< Number of indexes to drop */ | ||
| 5512 | dict_index_t **rename_index; /*!< Indexes to be dropped */ | ||
| 5513 | ulint n_rename_index; /*!< Number of indexes to rename */ | ||
| 5514 | dict_foreign_t **drop_fk; /*!< Foreign key constraints to drop */ | ||
| 5515 | ulint n_drop_fk; /*!< Number of foreign keys to drop */ | ||
| 5516 | 113006 | dict_foreign_t **add_fk = nullptr; /*!< Foreign key constraints to drop */ | |
| 5517 | ulint n_add_fk; /*!< Number of foreign keys to drop */ | ||
| 5518 | dict_table_t *indexed_table; /*!< Table where indexes are created */ | ||
| 5519 | mem_heap_t *heap; | ||
| 5520 | const char **col_names; | ||
| 5521 | int error; | ||
| 5522 | ulint max_col_len; | ||
| 5523 | 113006 | ulint add_autoinc_col_no = ULINT_UNDEFINED; | |
| 5524 | 113006 | ulonglong autoinc_col_max_value = 0; | |
| 5525 | 113006 | ulint fts_doc_col_no = ULINT_UNDEFINED; | |
| 5526 | 113006 | bool add_fts_doc_id = false; | |
| 5527 | 113006 | bool add_fts_doc_id_idx = false; | |
| 5528 | 113006 | bool add_fts_idx = false; | |
| 5529 | 113006 | dict_s_col_list *s_cols = nullptr; | |
| 5530 | 113006 | mem_heap_t *s_heap = nullptr; | |
| 5531 | 113006 | ulint encrypt_flag = 0; | |
| 5532 | |||
| 5533 |
1/2✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
|
113006 | DBUG_TRACE; |
| 5534 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56503 times.
|
113006 | assert(!ha_alter_info->handler_ctx); |
| 5535 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56503 times.
|
113006 | assert(ha_alter_info->create_info); |
| 5536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56503 times.
|
113006 | assert(!srv_read_only_mode); |
| 5537 | |||
| 5538 | 113006 | MONITOR_ATOMIC_INC(MONITOR_PENDING_ALTER_TABLE); | |
| 5539 | |||
| 5540 | #ifdef UNIV_DEBUG | ||
| 5541 |
3/4✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75468 times.
✓ Branch 3 taken 56503 times.
|
263942 | for (dict_index_t *index = m_prebuilt->table->first_index(); index; |
| 5542 |
1/2✓ Branch 0 taken 75468 times.
✗ Branch 1 not taken.
|
150936 | index = index->next()) { |
| 5543 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75468 times.
|
150936 | ut_ad(!index->to_be_dropped); |
| 5544 | } | ||
| 5545 | #endif /* UNIV_DEBUG */ | ||
| 5546 | |||
| 5547 |
1/2✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
|
113006 | ut_d(dict_sys_mutex_enter()); |
| 5548 |
1/2✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
|
113006 | ut_d(dict_table_check_for_dup_indexes(m_prebuilt->table, CHECK_ABORTED_OK)); |
| 5549 |
1/2✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
|
113006 | ut_d(dict_sys_mutex_exit()); |
| 5550 | |||
| 5551 | 113006 | indexed_table = m_prebuilt->table; | |
| 5552 | |||
| 5553 |
3/4✓ Branch 0 taken 56503 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 56502 times.
|
113006 | if (indexed_table->is_corrupted()) { |
| 5554 | /* The clustered index is corrupted. */ | ||
| 5555 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0)); |
| 5556 | 2 | return true; | |
| 5557 | } | ||
| 5558 | |||
| 5559 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 56473 times.
|
113004 | if (dict_table_is_discarded(indexed_table)) { |
| 5560 | 116 | Instant_Type type = innobase_support_instant( | |
| 5561 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
58 | ha_alter_info, m_prebuilt->table, this->table, altered_table); |
| 5562 | /* Even if some operations can be done instantly without rebuilding, they | ||
| 5563 | are still disallowed to behave like before. */ | ||
| 5564 | 116 | if (innobase_need_rebuild( | |
| 5565 | 58 | ha_alter_info, table, | |
| 5566 |
6/8✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 19 times.
|
96 | dict_table_is_file_per_table(m_prebuilt->table)) || |
| 5567 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
38 | (type == Instant_Type::INSTANT_VIRTUAL_ONLY || |
| 5568 | type == Instant_Type::INSTANT_ADD_DROP_COLUMN)) { | ||
| 5569 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
20 | my_error(ER_TABLESPACE_DISCARDED, MYF(0), indexed_table->name.m_name); |
| 5570 | 20 | return true; | |
| 5571 | } | ||
| 5572 | } | ||
| 5573 | |||
| 5574 |
2/2✓ Branch 0 taken 6658 times.
✓ Branch 1 taken 49834 times.
|
112984 | if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) { |
| 5575 | /* Nothing to do. Since there is no MDL protected, don't | ||
| 5576 | try to drop aborted indexes here. */ | ||
| 5577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6658 times.
|
13316 | assert(m_prebuilt->trx->dict_operation_lock_mode == 0); |
| 5578 | 13316 | return false; | |
| 5579 | } | ||
| 5580 | |||
| 5581 |
2/2✓ Branch 0 taken 1944 times.
✓ Branch 1 taken 47890 times.
|
99668 | if (is_instant(ha_alter_info)) { |
| 5582 | 7776 | Instant_Type type = innobase_support_instant(ha_alter_info, indexed_table, | |
| 5583 |
1/2✓ Branch 0 taken 1944 times.
✗ Branch 1 not taken.
|
3888 | this->table, altered_table); |
| 5584 | |||
| 5585 |
2/2✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 216 times.
|
3888 | if (type == Instant_Type::INSTANT_ADD_DROP_COLUMN) { |
| 5586 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1728 times.
|
3456 | ut_a(indexed_table->current_row_version < MAX_ROW_VERSION); |
| 5587 | } | ||
| 5588 | |||
| 5589 | 3888 | return false; | |
| 5590 | } | ||
| 5591 | |||
| 5592 | /* ALTER TABLE will not implicitly move a table from a single-table | ||
| 5593 | tablespace to the system tablespace when innodb_file_per_table=OFF. | ||
| 5594 | But it will implicitly move a table from the system tablespace to a | ||
| 5595 | single-table tablespace if innodb_file_per_table = ON. | ||
| 5596 | Tables found in a general tablespace will stay there unless ALTER | ||
| 5597 | TABLE contains another TABLESPACE=name. If that is found it will | ||
| 5598 | explicitly move a table to the named tablespace. | ||
| 5599 | So if you specify TABLESPACE=`innodb_system` a table can be moved | ||
| 5600 | into the system tablespace from either a general or file-per-table | ||
| 5601 | tablespace. But from then on, it is labeled as using a shared space | ||
| 5602 | (the create options have tablespace=='innodb_system' and the | ||
| 5603 | SHARED_SPACE flag is set in the table flags) so it can no longer be | ||
| 5604 | implicitly moved to a file-per-table tablespace. */ | ||
| 5605 |
1/2✓ Branch 0 taken 47890 times.
✗ Branch 1 not taken.
|
95780 | bool in_system_space = fsp_is_system_or_temp_tablespace(indexed_table->space); |
| 5606 | 95780 | bool is_file_per_table = | |
| 5607 |
4/4✓ Branch 0 taken 47720 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 33051 times.
✓ Branch 3 taken 14669 times.
|
95780 | !in_system_space && !DICT_TF_HAS_SHARED_SPACE(indexed_table->flags); |
| 5608 | #ifdef UNIV_DEBUG | ||
| 5609 | 95780 | bool in_general_space = | |
| 5610 |
4/4✓ Branch 0 taken 47720 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 14669 times.
✓ Branch 3 taken 33051 times.
|
95780 | !in_system_space && DICT_TF_HAS_SHARED_SPACE(indexed_table->flags); |
| 5611 | |||
| 5612 | /* The table being altered can only be in a system tablespace, | ||
| 5613 | or its own file-per-table tablespace, or a general tablespace. */ | ||
| 5614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47890 times.
|
95780 | ut_ad(1 == in_system_space + is_file_per_table + in_general_space); |
| 5615 | #endif /* UNIV_DEBUG */ | ||
| 5616 | |||
| 5617 | /* If server has passed a changed row format in the new table definition and | ||
| 5618 | the table isn't going to be rebuilt, revert that row_format change because it | ||
| 5619 | is an implicit change to the previously selected default row format. We want | ||
| 5620 | to keep the table using the original default row_format. */ | ||
| 5621 |
11/15✓ Branch 0 taken 3244 times.
✓ Branch 1 taken 44646 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3244 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44646 times.
✓ Branch 6 taken 3244 times.
✓ Branch 7 taken 157 times.
✓ Branch 8 taken 44489 times.
✓ Branch 9 taken 3260 times.
✓ Branch 10 taken 44630 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3244 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3244 times.
|
96094 | if (old_dd_tab->table().row_format() != new_dd_tab->table().row_format() && |
| 5622 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 141 times.
|
314 | !innobase_need_rebuild(ha_alter_info, altered_table, |
| 5623 |
1/2✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
|
314 | dict_table_is_file_per_table(m_prebuilt->table))) { |
| 5624 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
32 | adjust_row_format(this->table, altered_table, old_dd_tab, new_dd_tab); |
| 5625 | } | ||
| 5626 | |||
| 5627 | /* Make a copy for existing tablespace name */ | ||
| 5628 | 95780 | char tablespace[NAME_LEN] = {'\0'}; | |
| 5629 |
2/2✓ Branch 0 taken 14752 times.
✓ Branch 1 taken 33138 times.
|
95780 | if (indexed_table->tablespace) { |
| 5630 | 29504 | strcpy(tablespace, indexed_table->tablespace()); | |
| 5631 | } | ||
| 5632 | |||
| 5633 | 185072 | adjust_encryption_key_id(ha_alter_info->create_info, | |
| 5634 |
1/2✓ Branch 0 taken 47890 times.
✗ Branch 1 not taken.
|
95780 | &(new_dd_tab->options())); |
| 5635 | |||
| 5636 |
3/4✓ Branch 0 taken 14752 times.
✓ Branch 1 taken 33138 times.
✓ Branch 2 taken 47890 times.
✗ Branch 3 not taken.
|
95780 | create_table_info_t info(m_user_thd, altered_table, |
| 5637 | ha_alter_info->create_info, nullptr, nullptr, | ||
| 5638 | 95780 | indexed_table->tablespace ? tablespace : nullptr, | |
| 5639 | is_file_per_table, false, 0, 0, false); | ||
| 5640 | |||
| 5641 |
1/2✓ Branch 0 taken 47890 times.
✗ Branch 1 not taken.
|
95780 | info.set_tablespace_type(is_file_per_table); |
| 5642 | |||
| 5643 |
5/6✓ Branch 0 taken 22158 times.
✓ Branch 1 taken 25732 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22158 times.
✓ Branch 4 taken 25732 times.
✓ Branch 5 taken 22158 times.
|
140096 | if (ha_alter_info->handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION || |
| 5644 | 44316 | (Encryption::should_be_keyring_encrypted( | |
| 5645 | 44316 | ha_alter_info->create_info->explicit_encryption, | |
| 5646 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
44316 | ha_alter_info->create_info->encrypt_type.str) && |
| 5647 | ✗ | innobase_spatial_exist( | |
| 5648 | altered_table))) { // We need to make sure spatial index was not | ||
| 5649 | // added if this is to be keyring encrypted | ||
| 5650 |
1/2✓ Branch 0 taken 25732 times.
✗ Branch 1 not taken.
|
51464 | const char *invalid_opt = info.create_options_are_invalid(); |
| 5651 |
2/2✓ Branch 0 taken 174 times.
✓ Branch 1 taken 25558 times.
|
51464 | if (invalid_opt != nullptr) { |
| 5652 |
2/4✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
|
348 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), table_type(), invalid_opt); |
| 5653 | 348 | goto err_exit_no_heap; | |
| 5654 | } | ||
| 5655 | } | ||
| 5656 | |||
| 5657 | /* Check if any index name is reserved. */ | ||
| 5658 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 47715 times.
|
95432 | if (innobase_index_name_is_reserved(m_user_thd, |
| 5659 | 95432 | ha_alter_info->key_info_buffer, | |
| 5660 |
1/2✓ Branch 0 taken 47716 times.
✗ Branch 1 not taken.
|
95432 | ha_alter_info->key_count)) { |
| 5661 | 2 | err_exit_no_heap: | |
| 5662 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
|
376 | assert(m_prebuilt->trx->dict_operation_lock_mode == 0); |
| 5663 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | if (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { |
| 5664 |
1/2✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
|
376 | online_retry_drop_dict_indexes(m_prebuilt->table, false); |
| 5665 | } | ||
| 5666 | 376 | return true; | |
| 5667 | } | ||
| 5668 | |||
| 5669 | 95430 | indexed_table = m_prebuilt->table; | |
| 5670 | |||
| 5671 | /* Check that index keys are sensible */ | ||
| 5672 |
1/2✓ Branch 0 taken 47715 times.
✗ Branch 1 not taken.
|
95430 | error = innobase_check_index_keys(ha_alter_info, indexed_table); |
| 5673 | |||
| 5674 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47715 times.
|
95430 | if (error) { |
| 5675 | ✗ | goto err_exit_no_heap; | |
| 5676 | } | ||
| 5677 | |||
| 5678 | /* Prohibit renaming a column to something that the table | ||
| 5679 | already contains. */ | ||
| 5680 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 47649 times.
|
95430 | if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME) { |
| 5681 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 64 times.
|
132 | if (!ok_to_rename_column(ha_alter_info, table, altered_table, |
| 5682 |
1/2✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
|
132 | m_prebuilt->table, false, true)) { |
| 5683 | 4 | goto err_exit_no_heap; | |
| 5684 | } | ||
| 5685 | } | ||
| 5686 | |||
| 5687 |
3/4✓ Branch 0 taken 47713 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 47711 times.
|
95426 | if (!info.innobase_table_flags()) { |
| 5688 | 4 | goto err_exit_no_heap; | |
| 5689 | } | ||
| 5690 | |||
| 5691 | /* create_table_info_t::innobase_table_flags does not set encryption | ||
| 5692 | flags. There are places where it is done afterwards, there are places | ||
| 5693 | where it isn't done. We need to inspect all code paths and check if | ||
| 5694 | encryption flag can be set in one place. */ | ||
| 5695 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 46777 times.
|
95422 | if (Encryption::is_master_key_encryption( |
| 5696 | 95422 | ha_alter_info->create_info->encrypt_type.str)) { | |
| 5697 | /* Set the encryption flag. */ | ||
| 5698 | 1868 | byte *master_key = nullptr; | |
| 5699 | uint32_t master_key_id; | ||
| 5700 | |||
| 5701 | /* Check if keyring is ready. */ | ||
| 5702 | 1868 | Encryption::get_master_key(&master_key_id, &master_key); | |
| 5703 | |||
| 5704 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
|
1868 | if (master_key == nullptr) { |
| 5705 | ✗ | goto err_exit_no_heap; | |
| 5706 | } else { | ||
| 5707 |
1/2✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
|
1868 | my_free(master_key); |
| 5708 | 1868 | encrypt_flag = DICT_TF2_ENCRYPTION_FILE_PER_TABLE; | |
| 5709 | } | ||
| 5710 | } | ||
| 5711 | |||
| 5712 | 95422 | max_col_len = DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(info.flags()); | |
| 5713 | |||
| 5714 | /* Check each index's column length to make sure they do not | ||
| 5715 | exceed limit */ | ||
| 5716 |
2/2✓ Branch 0 taken 7811 times.
✓ Branch 1 taken 47707 times.
|
111036 | for (ulint i = 0; i < ha_alter_info->index_add_count; i++) { |
| 5717 | 15622 | const KEY *key = | |
| 5718 | 15622 | &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; | |
| 5719 | |||
| 5720 |
2/2✓ Branch 0 taken 470 times.
✓ Branch 1 taken 7341 times.
|
15622 | if (key->flags & HA_FULLTEXT) { |
| 5721 | /* The column length does not matter for | ||
| 5722 | fulltext search indexes. But, UNIQUE | ||
| 5723 | fulltext indexes are not supported. */ | ||
| 5724 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 470 times.
|
940 | assert(!(key->flags & HA_NOSAME)); |
| 5725 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 470 times.
|
940 | assert(!(key->flags & HA_KEYFLAG_MASK & |
| 5726 | ~(HA_FULLTEXT | HA_PACK_KEY | HA_BINARY_PACK_KEY))); | ||
| 5727 | 940 | add_fts_idx = true; | |
| 5728 | 940 | continue; | |
| 5729 | } | ||
| 5730 | |||
| 5731 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7337 times.
|
14682 | if (innobase_check_column_length(max_col_len, key)) { |
| 5732 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), max_col_len); |
| 5733 | 8 | goto err_exit_no_heap; | |
| 5734 | } | ||
| 5735 | } | ||
| 5736 | |||
| 5737 | /* Check existing index definitions for too-long column | ||
| 5738 | prefixes as well, in case max_col_len shrunk. */ | ||
| 5739 |
3/4✓ Branch 0 taken 47707 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64635 times.
✓ Branch 3 taken 47707 times.
|
224684 | for (const dict_index_t *index = indexed_table->first_index(); index; |
| 5740 |
1/2✓ Branch 0 taken 64635 times.
✗ Branch 1 not taken.
|
129270 | index = index->next()) { |
| 5741 |
2/2✓ Branch 0 taken 1124 times.
✓ Branch 1 taken 63511 times.
|
129270 | if (index->type & DICT_FTS) { |
| 5742 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2248 | assert(index->type == DICT_FTS || index->is_corrupted()); |
| 5743 | |||
| 5744 | /* We need to drop any corrupted fts indexes | ||
| 5745 | before we add a new fts index. */ | ||
| 5746 |
3/4✓ Branch 0 taken 941 times.
✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 941 times.
|
2248 | if (add_fts_idx && index->type & DICT_CORRUPT) { |
| 5747 | ✗ | ib_errf(m_user_thd, IB_LOG_LEVEL_ERROR, ER_INNODB_INDEX_CORRUPT, | |
| 5748 | "Fulltext index '%s' is corrupt. " | ||
| 5749 | "you should drop this index first.", | ||
| 5750 | index->name()); | ||
| 5751 | |||
| 5752 | ✗ | goto err_exit_no_heap; | |
| 5753 | } | ||
| 5754 | |||
| 5755 | 2248 | continue; | |
| 5756 | } | ||
| 5757 | |||
| 5758 |
3/4✓ Branch 0 taken 537430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 473919 times.
✓ Branch 3 taken 63511 times.
|
1074860 | for (ulint i = 0; i < dict_index_get_n_fields(index); i++) { |
| 5759 |
1/2✓ Branch 0 taken 473919 times.
✗ Branch 1 not taken.
|
947838 | const dict_field_t *field = index->get_field(i); |
| 5760 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 473919 times.
|
947838 | if (field->prefix_len > max_col_len) { |
| 5761 | ✗ | my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), max_col_len); | |
| 5762 | ✗ | goto err_exit_no_heap; | |
| 5763 | } | ||
| 5764 | } | ||
| 5765 | } | ||
| 5766 | |||
| 5767 | 95414 | n_drop_index = 0; | |
| 5768 | 95414 | n_drop_fk = 0; | |
| 5769 | |||
| 5770 |
1/2✓ Branch 0 taken 47707 times.
✗ Branch 1 not taken.
|
95414 | if (ha_alter_info->handler_flags & |
| 5771 | (INNOBASE_ALTER_NOREBUILD | INNOBASE_ALTER_REBUILD)) { | ||
| 5772 |
1/2✓ Branch 0 taken 47707 times.
✗ Branch 1 not taken.
|
95414 | heap = mem_heap_create(1024, UT_LOCATION_HERE); |
| 5773 | |||
| 5774 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 47643 times.
|
95414 | if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME) { |
| 5775 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
128 | col_names = innobase_get_col_names(ha_alter_info, altered_table, table, |
| 5776 | indexed_table, heap); | ||
| 5777 | } else { | ||
| 5778 | 95286 | col_names = nullptr; | |
| 5779 | } | ||
| 5780 | } else { | ||
| 5781 | ✗ | heap = nullptr; | |
| 5782 | ✗ | col_names = nullptr; | |
| 5783 | } | ||
| 5784 | |||
| 5785 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 47669 times.
|
95414 | if (ha_alter_info->handler_flags & Alter_inplace_info::DROP_FOREIGN_KEY) { |
| 5786 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
76 | assert(ha_alter_info->alter_info->drop_list.size() > 0); |
| 5787 | |||
| 5788 | drop_fk = static_cast<dict_foreign_t **>( | ||
| 5789 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
76 | mem_heap_alloc(heap, ha_alter_info->alter_info->drop_list.size() * |
| 5790 | sizeof(dict_foreign_t *))); | ||
| 5791 | |||
| 5792 |
3/4✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 38 times.
|
164 | for (const Alter_drop *drop : ha_alter_info->alter_info->drop_list) { |
| 5793 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 39 times.
|
88 | if (drop->type != Alter_drop::FOREIGN_KEY) { |
| 5794 | 10 | continue; | |
| 5795 | } | ||
| 5796 | |||
| 5797 | 78 | for (dict_foreign_set::iterator it = | |
| 5798 | 78 | m_prebuilt->table->foreign_set.begin(); | |
| 5799 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
86 | it != m_prebuilt->table->foreign_set.end(); ++it) { |
| 5800 | 86 | dict_foreign_t *foreign = *it; | |
| 5801 | 86 | const char *fid = strchr(foreign->id, '/'); | |
| 5802 | |||
| 5803 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
86 | assert(fid); |
| 5804 | /* If no database/ prefix was present in | ||
| 5805 | the FOREIGN KEY constraint name, compare | ||
| 5806 | to the full constraint name. */ | ||
| 5807 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
86 | fid = fid ? fid + 1 : foreign->id; |
| 5808 | |||
| 5809 |
3/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 4 times.
|
86 | if (!my_strcasecmp(system_charset_info, fid, drop->name)) { |
| 5810 | 78 | drop_fk[n_drop_fk++] = foreign; | |
| 5811 | 78 | goto found_fk; | |
| 5812 | } | ||
| 5813 | } | ||
| 5814 | |||
| 5815 | /* | ||
| 5816 | Since we check that foreign key to be dropped exists on SQL-layer, | ||
| 5817 | we should not come here unless there is some bug and data-dictionary | ||
| 5818 | and InnoDB dictionary cache got out of sync. | ||
| 5819 | */ | ||
| 5820 | ✗ | assert(0); | |
| 5821 | my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->name); | ||
| 5822 | goto err_exit; | ||
| 5823 | 78 | found_fk: | |
| 5824 | 78 | continue; | |
| 5825 | } | ||
| 5826 | |||
| 5827 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
76 | assert(n_drop_fk > 0); |
| 5828 | } else { | ||
| 5829 | 95338 | drop_fk = nullptr; | |
| 5830 | } | ||
| 5831 | |||
| 5832 |
2/2✓ Branch 0 taken 1932 times.
✓ Branch 1 taken 45775 times.
|
95414 | if (ha_alter_info->index_drop_count) { |
| 5833 | 3864 | dict_index_t *drop_primary = nullptr; | |
| 5834 | |||
| 5835 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1932 times.
|
3864 | assert(ha_alter_info->handler_flags & |
| 5836 | (Alter_inplace_info::DROP_INDEX | | ||
| 5837 | Alter_inplace_info::DROP_UNIQUE_INDEX | | ||
| 5838 | Alter_inplace_info::DROP_PK_INDEX)); | ||
| 5839 | /* Check which indexes to drop. */ | ||
| 5840 | 7728 | drop_index = static_cast<dict_index_t **>(mem_heap_alloc( | |
| 5841 |
1/2✓ Branch 0 taken 1932 times.
✗ Branch 1 not taken.
|
3864 | heap, (ha_alter_info->index_drop_count + 1) * sizeof *drop_index)); |
| 5842 | |||
| 5843 |
2/2✓ Branch 0 taken 1987 times.
✓ Branch 1 taken 1932 times.
|
7838 | for (uint i = 0; i < ha_alter_info->index_drop_count; i++) { |
| 5844 | 3974 | const KEY *key = ha_alter_info->index_drop_buffer[i]; | |
| 5845 | dict_index_t *index = | ||
| 5846 |
1/2✓ Branch 0 taken 1987 times.
✗ Branch 1 not taken.
|
3974 | dict_table_get_index_on_name(indexed_table, key->name); |
| 5847 | |||
| 5848 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1987 times.
|
3974 | if (!index) { |
| 5849 | ✗ | push_warning_printf(m_user_thd, Sql_condition::SL_WARNING, | |
| 5850 | HA_ERR_WRONG_INDEX, | ||
| 5851 | "InnoDB could not find key" | ||
| 5852 | " with name %s", | ||
| 5853 | ✗ | key->name); | |
| 5854 | } else { | ||
| 5855 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1987 times.
|
3974 | ut_ad(!index->to_be_dropped); |
| 5856 |
3/4✓ Branch 0 taken 1987 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1313 times.
✓ Branch 3 taken 674 times.
|
3974 | if (!index->is_clustered()) { |
| 5857 | 2626 | drop_index[n_drop_index++] = index; | |
| 5858 | } else { | ||
| 5859 | 1348 | drop_primary = index; | |
| 5860 | } | ||
| 5861 | } | ||
| 5862 | } | ||
| 5863 | |||
| 5864 | /* If all FULLTEXT indexes were removed, drop an | ||
| 5865 | internal FTS_DOC_ID_INDEX as well, unless it exists in | ||
| 5866 | the table. */ | ||
| 5867 | |||
| 5868 | 3864 | if (innobase_fulltext_exist(table) && | |
| 5869 |
6/6✓ Branch 0 taken 131 times.
✓ Branch 1 taken 1801 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 1915 times.
✓ Branch 5 taken 17 times.
|
4088 | !innobase_fulltext_exist(altered_table) && |
| 5870 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 95 times.
|
224 | !DICT_TF2_FLAG_IS_SET(indexed_table, DICT_TF2_FTS_HAS_DOC_ID)) { |
| 5871 | 34 | dict_index_t *fts_doc_index = indexed_table->fts_doc_id_index; | |
| 5872 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
34 | ut_ad(fts_doc_index); |
| 5873 | |||
| 5874 | // Add some fault tolerance for non-debug builds. | ||
| 5875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
34 | if (fts_doc_index == nullptr) { |
| 5876 | ✗ | goto check_if_can_drop_indexes; | |
| 5877 | } | ||
| 5878 | |||
| 5879 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
34 | assert(!fts_doc_index->to_be_dropped); |
| 5880 | |||
| 5881 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 5 times.
|
74 | for (uint i = 0; i < table->s->keys; i++) { |
| 5882 |
3/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 20 times.
|
64 | if (!my_strcasecmp(system_charset_info, FTS_DOC_ID_INDEX_NAME, |
| 5883 | table->key_info[i].name)) { | ||
| 5884 | /* The index exists in the MySQL | ||
| 5885 | data dictionary. Do not drop it, | ||
| 5886 | even though it is no longer needed | ||
| 5887 | by InnoDB fulltext search. */ | ||
| 5888 | 24 | goto check_if_can_drop_indexes; | |
| 5889 | } | ||
| 5890 | } | ||
| 5891 | |||
| 5892 | 10 | drop_index[n_drop_index++] = fts_doc_index; | |
| 5893 | } | ||
| 5894 | |||
| 5895 | 3830 | check_if_can_drop_indexes: | |
| 5896 | /* Check if the indexes can be dropped. */ | ||
| 5897 | |||
| 5898 | /* Prevent a race condition between DROP INDEX and | ||
| 5899 | CREATE TABLE adding FOREIGN KEY constraints. */ | ||
| 5900 |
1/2✓ Branch 0 taken 1932 times.
✗ Branch 1 not taken.
|
3864 | row_mysql_lock_data_dictionary(m_prebuilt->trx, UT_LOCATION_HERE); |
| 5901 | |||
| 5902 |
2/2✓ Branch 0 taken 666 times.
✓ Branch 1 taken 1266 times.
|
3864 | if (!n_drop_index) { |
| 5903 | 1332 | drop_index = nullptr; | |
| 5904 | } else { | ||
| 5905 | /* Flag all indexes that are to be dropped. */ | ||
| 5906 |
2/2✓ Branch 0 taken 1318 times.
✓ Branch 1 taken 1266 times.
|
5168 | for (ulint i = 0; i < n_drop_index; i++) { |
| 5907 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1318 times.
|
2636 | ut_ad(!drop_index[i]->to_be_dropped); |
| 5908 | 2636 | drop_index[i]->to_be_dropped = 1; | |
| 5909 | } | ||
| 5910 | } | ||
| 5911 | |||
| 5912 |
2/2✓ Branch 0 taken 1318 times.
✓ Branch 1 taken 1932 times.
|
6500 | for (uint i = 0; i < n_drop_index; i++) { |
| 5913 | 2636 | dict_index_t *index = drop_index[i]; | |
| 5914 | |||
| 5915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1318 times.
|
2636 | if (innobase_check_foreign_key_index(ha_alter_info, index, indexed_table, |
| 5916 |
1/2✓ Branch 0 taken 1318 times.
✗ Branch 1 not taken.
|
2636 | col_names, m_prebuilt->trx, drop_fk, |
| 5917 | n_drop_fk)) { | ||
| 5918 | ✗ | row_mysql_unlock_data_dictionary(m_prebuilt->trx); | |
| 5919 | ✗ | m_prebuilt->trx->error_index = index; | |
| 5920 | ✗ | print_error(HA_ERR_DROP_INDEX_FK, MYF(0)); | |
| 5921 | ✗ | goto err_exit; | |
| 5922 | } | ||
| 5923 | } | ||
| 5924 | |||
| 5925 | /* If a primary index is dropped, need to check | ||
| 5926 | any depending foreign constraints get affected */ | ||
| 5927 |
4/6✓ Branch 0 taken 674 times.
✓ Branch 1 taken 1258 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 674 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1932 times.
|
5212 | if (drop_primary && innobase_check_foreign_key_index( |
| 5928 | ha_alter_info, drop_primary, indexed_table, | ||
| 5929 |
1/2✓ Branch 0 taken 674 times.
✗ Branch 1 not taken.
|
1348 | col_names, m_prebuilt->trx, drop_fk, n_drop_fk)) { |
| 5930 | ✗ | row_mysql_unlock_data_dictionary(m_prebuilt->trx); | |
| 5931 | ✗ | print_error(HA_ERR_DROP_INDEX_FK, MYF(0)); | |
| 5932 | ✗ | goto err_exit; | |
| 5933 | } | ||
| 5934 | |||
| 5935 |
1/2✓ Branch 0 taken 1932 times.
✗ Branch 1 not taken.
|
3864 | row_mysql_unlock_data_dictionary(m_prebuilt->trx); |
| 5936 | } else { | ||
| 5937 | 91550 | drop_index = nullptr; | |
| 5938 | } | ||
| 5939 | |||
| 5940 | 95414 | n_rename_index = ha_alter_info->index_rename_count; | |
| 5941 | 95414 | rename_index = nullptr; | |
| 5942 | |||
| 5943 | /* Create a list of dict_index_t objects that are to be renamed, | ||
| 5944 | also checking for requests to rename nonexistent indexes. If | ||
| 5945 | the table is going to be rebuilt (new_clustered == true in | ||
| 5946 | prepare_inplace_alter_table_dict()), then this can be skipped, | ||
| 5947 | but we don't for simplicity (we have not determined the value of | ||
| 5948 | new_clustered yet). */ | ||
| 5949 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 47623 times.
|
95414 | if (n_rename_index > 0) { |
| 5950 | rename_index = static_cast<dict_index_t **>( | ||
| 5951 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
168 | mem_heap_alloc(heap, n_rename_index * sizeof(*rename_index))); |
| 5952 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 84 times.
|
338 | for (ulint i = 0; i < n_rename_index; i++) { |
| 5953 | dict_index_t *index; | ||
| 5954 | 170 | const char *old_name = | |
| 5955 | 170 | ha_alter_info->index_rename_buffer[i].old_key->name; | |
| 5956 | |||
| 5957 |
1/2✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
|
170 | index = dict_table_get_index_on_name(indexed_table, old_name); |
| 5958 | |||
| 5959 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
|
170 | if (index == nullptr) { |
| 5960 | ✗ | my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), old_name, | |
| 5961 | ✗ | m_prebuilt->table->name.m_name); | |
| 5962 | ✗ | goto err_exit; | |
| 5963 | } | ||
| 5964 | |||
| 5965 | 170 | rename_index[i] = index; | |
| 5966 | } | ||
| 5967 | } | ||
| 5968 | |||
| 5969 | 95414 | n_add_fk = 0; | |
| 5970 | |||
| 5971 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 47613 times.
|
95414 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_FOREIGN_KEY) { |
| 5972 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
188 | ut_ad(!m_prebuilt->trx->check_foreigns); |
| 5973 | |||
| 5974 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
188 | alter_fill_stored_column(altered_table, m_prebuilt->table, &s_cols, |
| 5975 | &s_heap); | ||
| 5976 | |||
| 5977 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
188 | add_fk = static_cast<dict_foreign_t **>(mem_heap_zalloc( |
| 5978 | heap, | ||
| 5979 | 188 | ha_alter_info->alter_info->key_list.size() * sizeof(dict_foreign_t *))); | |
| 5980 | |||
| 5981 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 90 times.
|
188 | if (!innobase_get_foreign_key_info(ha_alter_info, table_share, |
| 5982 | 188 | m_prebuilt->table, col_names, drop_index, | |
| 5983 | n_drop_index, add_fk, &n_add_fk, | ||
| 5984 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
188 | m_prebuilt->trx, s_cols)) { |
| 5985 | 8 | err_exit: | |
| 5986 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
10 | if (n_drop_index) { |
| 5987 | ✗ | row_mysql_lock_data_dictionary(m_prebuilt->trx, UT_LOCATION_HERE); | |
| 5988 | |||
| 5989 | /* Clear the to_be_dropped flags, which might | ||
| 5990 | have been set at this point. */ | ||
| 5991 | ✗ | for (ulint i = 0; i < n_drop_index; i++) { | |
| 5992 | ✗ | ut_ad(drop_index[i]->is_committed()); | |
| 5993 | ✗ | drop_index[i]->to_be_dropped = 0; | |
| 5994 | } | ||
| 5995 | |||
| 5996 | ✗ | row_mysql_unlock_data_dictionary(m_prebuilt->trx); | |
| 5997 | } | ||
| 5998 | |||
| 5999 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
10 | if (heap) { |
| 6000 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
10 | mem_heap_free(heap); |
| 6001 | } | ||
| 6002 | |||
| 6003 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
10 | if (s_cols != nullptr) { |
| 6004 | 2 | ut::delete_(s_cols); | |
| 6005 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | mem_heap_free(s_heap); |
| 6006 | } | ||
| 6007 | |||
| 6008 | 10 | goto err_exit_no_heap; | |
| 6009 | } | ||
| 6010 | |||
| 6011 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 87 times.
|
180 | if (s_cols != nullptr) { |
| 6012 | 6 | ut::delete_(s_cols); | |
| 6013 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | mem_heap_free(s_heap); |
| 6014 | } | ||
| 6015 | } | ||
| 6016 | |||
| 6017 |
4/4✓ Branch 0 taken 46272 times.
✓ Branch 1 taken 1431 times.
✓ Branch 2 taken 11940 times.
✓ Branch 3 taken 35763 times.
|
187950 | if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA) || |
| 6018 |
2/2✓ Branch 0 taken 22108 times.
✓ Branch 1 taken 24164 times.
|
92544 | ((ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) == |
| 6019 | 44216 | Alter_inplace_info::CHANGE_CREATE_OPTION && | |
| 6020 |
2/2✓ Branch 0 taken 10509 times.
✓ Branch 1 taken 11599 times.
|
44216 | !innobase_need_rebuild( |
| 6021 | 44216 | ha_alter_info, table, | |
| 6022 |
1/2✓ Branch 0 taken 22108 times.
✗ Branch 1 not taken.
|
44216 | dict_table_is_file_per_table(m_prebuilt->table)))) { |
| 6023 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | if (heap) { |
| 6024 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
47760 | ha_alter_info->handler_ctx = new (m_user_thd->mem_root) |
| 6025 | ha_innobase_inplace_ctx(m_prebuilt, drop_index, n_drop_index, | ||
| 6026 | rename_index, n_rename_index, drop_fk, | ||
| 6027 | n_drop_fk, add_fk, n_add_fk, | ||
| 6028 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | ha_alter_info->online, heap, indexed_table, |
| 6029 | col_names, ULINT_UNDEFINED, 0, 0); | ||
| 6030 | } | ||
| 6031 | |||
| 6032 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11940 times.
|
23880 | assert(m_prebuilt->trx->dict_operation_lock_mode == 0); |
| 6033 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | if (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { |
| 6034 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | online_retry_drop_dict_indexes(m_prebuilt->table, false); |
| 6035 | } | ||
| 6036 | |||
| 6037 | 47760 | if ((ha_alter_info->handler_flags & | |
| 6038 |
3/4✓ Branch 0 taken 87 times.
✓ Branch 1 taken 11853 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11940 times.
|
24054 | Alter_inplace_info::DROP_VIRTUAL_COLUMN) && |
| 6039 |
2/4✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
|
174 | prepare_inplace_drop_virtual(ha_alter_info, table)) { |
| 6040 | ✗ | return true; | |
| 6041 | } | ||
| 6042 | |||
| 6043 | 47760 | if ((ha_alter_info->handler_flags & | |
| 6044 |
3/4✓ Branch 0 taken 147 times.
✓ Branch 1 taken 11793 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11940 times.
|
24174 | Alter_inplace_info::ADD_VIRTUAL_COLUMN) && |
| 6045 |
2/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 147 times.
|
294 | prepare_inplace_add_virtual(ha_alter_info, altered_table, table)) { |
| 6046 | ✗ | return true; | |
| 6047 | } | ||
| 6048 | |||
| 6049 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | if (ha_alter_info->handler_ctx != nullptr) { |
| 6050 | 23880 | ha_innobase_inplace_ctx *ctx = | |
| 6051 | static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | ||
| 6052 | 47760 | if ((ha_alter_info->handler_flags & | |
| 6053 | 21018 | Alter_inplace_info::CHANGE_CREATE_OPTION) && | |
| 6054 | 21018 | ha_alter_info->create_info | |
| 6055 |
5/6✓ Branch 0 taken 10509 times.
✓ Branch 1 taken 1431 times.
✓ Branch 2 taken 5032 times.
✓ Branch 3 taken 5477 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 11940 times.
|
33944 | ->m_implicit_tablespace_autoextend_size_change && |
| 6056 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5032 times.
|
10064 | prepare_inplace_change_implicit_tablespace_option( |
| 6057 |
1/2✓ Branch 0 taken 5032 times.
✗ Branch 1 not taken.
|
10064 | m_user_thd, ha_alter_info, ctx->old_table)) { |
| 6058 | ✗ | return true; | |
| 6059 | } | ||
| 6060 |
1/2✓ Branch 0 taken 11940 times.
✗ Branch 1 not taken.
|
23880 | return dd_prepare_inplace_alter_table(m_user_thd, ctx->old_table, |
| 6061 | 23880 | ctx->new_table, old_dd_tab); | |
| 6062 | } else { | ||
| 6063 | ✗ | return false; | |
| 6064 | } | ||
| 6065 | } | ||
| 6066 | |||
| 6067 | /* If we are to build a full-text search index, check whether | ||
| 6068 | the table already has a DOC ID column. If not, we will need to | ||
| 6069 | add a Doc ID hidden column and rebuild the primary index */ | ||
| 6070 |
2/2✓ Branch 0 taken 490 times.
✓ Branch 1 taken 35273 times.
|
71526 | if (innobase_fulltext_exist(altered_table)) { |
| 6071 | ulint doc_col_no; | ||
| 6072 | 980 | ulint num_v = 0; | |
| 6073 | |||
| 6074 |
3/4✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✓ Branch 3 taken 368 times.
|
980 | if (!innobase_fts_check_doc_id_col(m_prebuilt->table, altered_table, |
| 6075 | &fts_doc_col_no, &num_v)) { | ||
| 6076 | 244 | fts_doc_col_no = altered_table->s->fields - num_v; | |
| 6077 | 244 | add_fts_doc_id = true; | |
| 6078 | 244 | add_fts_doc_id_idx = true; | |
| 6079 | |||
| 6080 |
1/2✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
|
244 | push_warning_printf(m_user_thd, Sql_condition::SL_WARNING, |
| 6081 | HA_ERR_WRONG_INDEX, | ||
| 6082 | "InnoDB rebuilding table to add" | ||
| 6083 | " column " FTS_DOC_ID_COL_NAME); | ||
| 6084 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 367 times.
|
736 | } else if (fts_doc_col_no == ULINT_UNDEFINED) { |
| 6085 | 2 | goto err_exit; | |
| 6086 | } | ||
| 6087 | |||
| 6088 |
3/6✓ Branch 0 taken 489 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 352 times.
✗ Branch 5 not taken.
|
978 | switch (innobase_fts_check_doc_id_index(m_prebuilt->table, altered_table, |
| 6089 | &doc_col_no)) { | ||
| 6090 | 274 | case FTS_NOT_EXIST_DOC_ID_INDEX: | |
| 6091 | 274 | add_fts_doc_id_idx = true; | |
| 6092 | 274 | break; | |
| 6093 | ✗ | case FTS_INCORRECT_DOC_ID_INDEX: | |
| 6094 | ✗ | my_error(ER_INNODB_FT_WRONG_DOCID_INDEX, MYF(0), FTS_DOC_ID_INDEX_NAME); | |
| 6095 | ✗ | goto err_exit; | |
| 6096 | 704 | case FTS_EXIST_DOC_ID_INDEX: | |
| 6097 |
3/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
704 | assert(doc_col_no == fts_doc_col_no || doc_col_no == ULINT_UNDEFINED || |
| 6098 | (ha_alter_info->handler_flags & | ||
| 6099 | (Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | | ||
| 6100 | Alter_inplace_info::DROP_STORED_COLUMN | | ||
| 6101 | Alter_inplace_info::ADD_STORED_BASE_COLUMN))); | ||
| 6102 | } | ||
| 6103 | } | ||
| 6104 | |||
| 6105 | /* See if an AUTO_INCREMENT column was added. */ | ||
| 6106 | 71524 | uint i = 0; | |
| 6107 | 71524 | ulint num_v = 0; | |
| 6108 | 71524 | List_iterator_fast<Create_field> cf_it( | |
| 6109 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | ha_alter_info->alter_info->create_list); |
| 6110 |
2/2✓ Branch 0 taken 271249 times.
✓ Branch 1 taken 35762 times.
|
614022 | while (const Create_field *new_field = cf_it++) { |
| 6111 | const Field *field; | ||
| 6112 | |||
| 6113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 271249 times.
|
542498 | assert(i < altered_table->s->fields); |
| 6114 | |||
| 6115 |
2/2✓ Branch 0 taken 3558620 times.
✓ Branch 1 taken 17936 times.
|
7153112 | for (uint old_i = 0; table->field[old_i]; old_i++) { |
| 6116 |
2/2✓ Branch 0 taken 253313 times.
✓ Branch 1 taken 3305307 times.
|
7117240 | if (new_field->field == table->field[old_i]) { |
| 6117 | 506626 | goto found_col; | |
| 6118 | } | ||
| 6119 | } | ||
| 6120 | |||
| 6121 | /* This is an added column. */ | ||
| 6122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17936 times.
|
35872 | assert(!new_field->field); |
| 6123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17936 times.
|
35872 | assert(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN); |
| 6124 | |||
| 6125 | 35872 | field = altered_table->field[i]; | |
| 6126 | |||
| 6127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17936 times.
|
35872 | assert(((field->auto_flags & Field::NEXT_NUMBER) != 0) == |
| 6128 | field->is_flag_set(AUTO_INCREMENT_FLAG)); | ||
| 6129 | |||
| 6130 |
2/2✓ Branch 0 taken 17895 times.
✓ Branch 1 taken 41 times.
|
35872 | if (field->is_flag_set(AUTO_INCREMENT_FLAG)) { |
| 6131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
82 | if (add_autoinc_col_no != ULINT_UNDEFINED) { |
| 6132 | /* This should have been blocked earlier. */ | ||
| 6133 | ✗ | my_error(ER_WRONG_AUTO_KEY, MYF(0)); | |
| 6134 | ✗ | ut_d(ut_error); | |
| 6135 | ut_o(goto err_exit); | ||
| 6136 | } | ||
| 6137 | |||
| 6138 | /* Get the col no of the old table non-virtual column array */ | ||
| 6139 | 82 | add_autoinc_col_no = i - num_v; | |
| 6140 | |||
| 6141 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
82 | autoinc_col_max_value = field->get_max_int_value(); |
| 6142 | } | ||
| 6143 | 35790 | found_col: | |
| 6144 |
4/4✓ Branch 0 taken 1514 times.
✓ Branch 1 taken 269735 times.
✓ Branch 2 taken 1398 times.
✓ Branch 3 taken 116 times.
|
542498 | if (innobase_is_v_fld(new_field)) { |
| 6145 | 2796 | ++num_v; | |
| 6146 | } | ||
| 6147 | |||
| 6148 | 542498 | i++; | |
| 6149 | } | ||
| 6150 | |||
| 6151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(heap); |
| 6152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(m_user_thd == m_prebuilt->trx->mysql_thd); |
| 6153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35762 times.
|
71524 | assert(!ha_alter_info->handler_ctx); |
| 6154 | |||
| 6155 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
143048 | ha_alter_info->handler_ctx = new (m_user_thd->mem_root) |
| 6156 | ha_innobase_inplace_ctx(m_prebuilt, drop_index, n_drop_index, | ||
| 6157 | rename_index, n_rename_index, drop_fk, n_drop_fk, | ||
| 6158 | 71524 | add_fk, n_add_fk, ha_alter_info->online, heap, | |
| 6159 | 71524 | m_prebuilt->table, col_names, add_autoinc_col_no, | |
| 6160 |
1/2✓ Branch 0 taken 35762 times.
✗ Branch 1 not taken.
|
71524 | ha_alter_info->create_info->auto_increment_value, |
| 6161 | autoinc_col_max_value); | ||
| 6162 | |||
| 6163 | 71524 | return prepare_inplace_alter_table_dict( | |
| 6164 | 71524 | ha_alter_info, altered_table, table, old_dd_tab, new_dd_tab, | |
| 6165 |
1/2✓ Branch 0 taken 35623 times.
✗ Branch 1 not taken.
|
143048 | table_share->table_name.str, info.flags(), info.flags2() | encrypt_flag, |
| 6166 | 71246 | fts_doc_col_no, add_fts_doc_id, add_fts_doc_id_idx, m_prebuilt); | |
| 6167 | 112728 | } | |
| 6168 | |||
| 6169 | /** Check that the column is part of a virtual index(index contains | ||
| 6170 | virtual column) in the table | ||
| 6171 | @param[in] table Table containing column | ||
| 6172 | @param[in] col column to be checked | ||
| 6173 | @return true if this column is indexed with other virtual columns */ | ||
| 6174 | 93 | static bool dict_col_in_v_indexes(dict_table_t *table, dict_col_t *col) { | |
| 6175 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 93 times.
|
279 | for (dict_index_t *index = table->first_index()->next(); index != nullptr; |
| 6176 | 186 | index = index->next()) { | |
| 6177 |
1/2✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
|
186 | if (!dict_index_has_virtual(index)) { |
| 6178 | 186 | continue; | |
| 6179 | } | ||
| 6180 | ✗ | for (ulint k = 0; k < index->n_fields; k++) { | |
| 6181 | ✗ | dict_field_t *field = index->get_field(k); | |
| 6182 | ✗ | if (field->col->ind == col->ind) { | |
| 6183 | ✗ | return (true); | |
| 6184 | } | ||
| 6185 | } | ||
| 6186 | } | ||
| 6187 | |||
| 6188 | 93 | return (false); | |
| 6189 | } | ||
| 6190 | |||
| 6191 | /* Check whether a columnn length change alter operation requires | ||
| 6192 | to rebuild the template. | ||
| 6193 | @param[in] altered_table TABLE object for new version of table. | ||
| 6194 | @param[in] ha_alter_info Structure describing changes to be done | ||
| 6195 | by ALTER TABLE and holding data used | ||
| 6196 | during in-place alter. | ||
| 6197 | @param[in] table table being altered | ||
| 6198 | @return true if needs rebuild. */ | ||
| 6199 | 6 | static bool alter_templ_needs_rebuild(TABLE *altered_table, | |
| 6200 | Alter_inplace_info *ha_alter_info, | ||
| 6201 | dict_table_t *table) { | ||
| 6202 | 6 | ulint i = 0; | |
| 6203 | List_iterator_fast<Create_field> cf_it( | ||
| 6204 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | ha_alter_info->alter_info->create_list); |
| 6205 | |||
| 6206 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
|
16 | for (Field **fp = altered_table->field; *fp; fp++, i++) { |
| 6207 | 10 | cf_it.rewind(); | |
| 6208 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
|
30 | while (const Create_field *cf = cf_it++) { |
| 6209 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 20 times.
|
126 | for (ulint j = 0; j < table->n_cols; j++) { |
| 6210 |
1/2✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
|
106 | dict_col_t *cols = table->get_col(j); |
| 6211 |
4/6✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 106 times.
|
199 | if (cf->max_display_width_in_bytes() > cols->len && |
| 6212 |
2/4✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
|
93 | dict_col_in_v_indexes(table, cols)) { |
| 6213 | ✗ | return (true); | |
| 6214 | } | ||
| 6215 | } | ||
| 6216 | 20 | } | |
| 6217 | } | ||
| 6218 | |||
| 6219 | 6 | return (false); | |
| 6220 | } | ||
| 6221 | |||
| 6222 | /** Get the name of an erroneous key. | ||
| 6223 | @param[in] error_key_num InnoDB number of the erroneus key | ||
| 6224 | @param[in] ha_alter_info changes that were being performed | ||
| 6225 | @param[in] table InnoDB table | ||
| 6226 | @return the name of the erroneous key */ | ||
| 6227 | 2 | static const char *get_error_key_name(ulint error_key_num, | |
| 6228 | const Alter_inplace_info *ha_alter_info, | ||
| 6229 | const dict_table_t *table) { | ||
| 6230 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error_key_num == ULINT_UNDEFINED) { |
| 6231 | ✗ | return (FTS_DOC_ID_INDEX_NAME); | |
| 6232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | } else if (ha_alter_info->key_count == 0) { |
| 6233 | ✗ | return (table->first_index()->name); | |
| 6234 | } else { | ||
| 6235 | 2 | return (ha_alter_info->key_info_buffer[error_key_num].name); | |
| 6236 | } | ||
| 6237 | } | ||
| 6238 | |||
| 6239 | template <typename Table> | ||
| 6240 | 112052 | bool ha_innobase::inplace_alter_table_impl(TABLE *altered_table, | |
| 6241 | Alter_inplace_info *ha_alter_info) { | ||
| 6242 | 112052 | dict_add_v_col_t *add_v = nullptr; | |
| 6243 | 112052 | dict_vcol_templ_t *s_templ = nullptr; | |
| 6244 | 112052 | dict_vcol_templ_t *old_templ = nullptr; | |
| 6245 | 112052 | struct TABLE *eval_table = altered_table; | |
| 6246 | 112052 | bool rebuild_templ = false; | |
| 6247 |
1/2✓ Branch 0 taken 56026 times.
✗ Branch 1 not taken.
|
112052 | DBUG_TRACE; |
| 6248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56026 times.
|
112052 | assert(!srv_read_only_mode); |
| 6249 | |||
| 6250 |
2/4✓ Branch 0 taken 56026 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56026 times.
|
112052 | ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_X)); |
| 6251 |
2/4✓ Branch 0 taken 56026 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56026 times.
|
112052 | ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S)); |
| 6252 | |||
| 6253 |
3/4✓ Branch 0 taken 54364 times.
✓ Branch 1 taken 1662 times.
✓ Branch 2 taken 54364 times.
✗ Branch 3 not taken.
|
112052 | DEBUG_SYNC(m_user_thd, "innodb_inplace_alter_table_enter"); |
| 6254 | |||
| 6255 | 222224 | auto all_ok = [=]() -> bool { | |
| 6256 |
3/4✓ Branch 0 taken 4125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50130 times.
✓ Branch 3 taken 1662 times.
|
55917 | DEBUG_SYNC(m_user_thd, "innodb_after_inplace_alter_table"); |
| 6257 | 55917 | return false; | |
| 6258 | }; | ||
| 6259 | |||
| 6260 | 218177 | auto success = [&]() -> bool { | |
| 6261 | 35375 | ut_d(dict_sys_mutex_enter()); | |
| 6262 | 35375 | ut_d(dict_table_check_for_dup_indexes(m_prebuilt->table, CHECK_PARTIAL_OK)); | |
| 6263 | 35375 | ut_d(dict_sys_mutex_exit()); | |
| 6264 | /* prebuilt->table->n_ref_count can be anything here, | ||
| 6265 | given that we hold at most a shared lock on the table. */ | ||
| 6266 | 35375 | return all_ok(); | |
| 6267 | }; | ||
| 6268 | |||
| 6269 |
6/6✓ Branch 0 taken 47721 times.
✓ Branch 1 taken 8305 times.
✓ Branch 2 taken 1728 times.
✓ Branch 3 taken 45993 times.
✓ Branch 4 taken 10033 times.
✓ Branch 5 taken 45993 times.
|
207494 | if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA) || |
| 6270 | 95442 | is_instant(ha_alter_info)) { | |
| 6271 |
1/2✓ Branch 0 taken 10033 times.
✗ Branch 1 not taken.
|
20066 | return all_ok(); |
| 6272 | } | ||
| 6273 | |||
| 6274 | 183972 | if (((ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) == | |
| 6275 |
4/4✓ Branch 0 taken 22103 times.
✓ Branch 1 taken 23890 times.
✓ Branch 2 taken 10509 times.
✓ Branch 3 taken 35484 times.
|
136192 | Alter_inplace_info::CHANGE_CREATE_OPTION && |
| 6276 |
2/2✓ Branch 0 taken 10509 times.
✓ Branch 1 taken 11594 times.
|
44206 | !innobase_need_rebuild( |
| 6277 | 44206 | ha_alter_info, table, | |
| 6278 |
1/2✓ Branch 0 taken 22103 times.
✗ Branch 1 not taken.
|
44206 | dict_table_is_file_per_table(m_prebuilt->table)))) { |
| 6279 |
1/2✓ Branch 0 taken 10509 times.
✗ Branch 1 not taken.
|
21018 | return all_ok(); |
| 6280 | } | ||
| 6281 | |||
| 6282 | 70968 | ha_innobase_inplace_ctx *ctx = | |
| 6283 | 70968 | static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | |
| 6284 | |||
| 6285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35484 times.
|
70968 | assert(ctx); |
| 6286 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35484 times.
|
70968 | assert(ctx->trx); |
| 6287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35484 times.
|
70968 | assert(ctx->prebuilt == m_prebuilt); |
| 6288 | |||
| 6289 |
1/2✓ Branch 0 taken 35484 times.
✗ Branch 1 not taken.
|
70968 | dict_index_t *pk = m_prebuilt->table->first_index(); |
| 6290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35484 times.
|
70968 | ut_ad(pk != nullptr); |
| 6291 | |||
| 6292 | /* For partitioned tables this could be already allocated from a | ||
| 6293 | previous partition invocation. For normal tables this is NULL. */ | ||
| 6294 | 70968 | ut::delete_(ctx->m_stage); | |
| 6295 | |||
| 6296 |
1/2✓ Branch 0 taken 35484 times.
✗ Branch 1 not taken.
|
70968 | ctx->m_stage = ut::new_withkey<Alter_stage>(UT_NEW_THIS_FILE_PSI_KEY, pk); |
| 6297 | |||
| 6298 |
5/6✓ Branch 0 taken 35476 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35476 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 35476 times.
|
141920 | if (m_prebuilt->table->ibd_file_missing || |
| 6299 | 70952 | dict_table_is_discarded(m_prebuilt->table)) { | |
| 6300 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
16 | return success(); |
| 6301 | } | ||
| 6302 | |||
| 6303 | /* If we are doing a table rebuilding or having added virtual | ||
| 6304 | columns in the same clause, we will need to build a table template | ||
| 6305 | that carries translation information between MySQL TABLE and InnoDB | ||
| 6306 | table, which indicates the virtual columns and their base columns | ||
| 6307 | info. This is used to do the computation callback, so that the | ||
| 6308 | data in base columns can be extracted send to server. | ||
| 6309 | If the Column length changes and it is a part of virtual | ||
| 6310 | index then we need to rebuild the template. */ | ||
| 6311 | 70952 | rebuild_templ = | |
| 6312 |
2/2✓ Branch 0 taken 5175 times.
✓ Branch 1 taken 30301 times.
|
81302 | ctx->need_rebuild() || |
| 6313 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5169 times.
|
10350 | ((ha_alter_info->handler_flags & |
| 6314 | 12 | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH) && | |
| 6315 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
12 | alter_templ_needs_rebuild(altered_table, ha_alter_info, ctx->new_table)); |
| 6316 | |||
| 6317 |
4/4✓ Branch 0 taken 1061 times.
✓ Branch 1 taken 34415 times.
✓ Branch 2 taken 823 times.
✓ Branch 3 taken 238 times.
|
70952 | if ((ctx->new_table->n_v_cols > 0) && rebuild_templ) { |
| 6318 | /* Save the templ if isn't NULL so as to restore the | ||
| 6319 | original state in case of alter operation failures. */ | ||
| 6320 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 823 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 823 times.
|
1646 | if (ctx->new_table->vc_templ != nullptr && !ctx->need_rebuild()) { |
| 6321 | ✗ | old_templ = ctx->new_table->vc_templ; | |
| 6322 | } | ||
| 6323 |
1/2✓ Branch 0 taken 823 times.
✗ Branch 1 not taken.
|
1646 | s_templ = ut::new_withkey<dict_vcol_templ_t>(UT_NEW_THIS_FILE_PSI_KEY); |
| 6324 | 1646 | s_templ->vtempl = nullptr; | |
| 6325 | |||
| 6326 |
1/2✓ Branch 0 taken 823 times.
✗ Branch 1 not taken.
|
1646 | innobase_build_v_templ(altered_table, ctx->new_table, s_templ, nullptr, |
| 6327 | false, nullptr); | ||
| 6328 | |||
| 6329 | 1646 | ctx->new_table->vc_templ = s_templ; | |
| 6330 |
2/2✓ Branch 0 taken 169 times.
✓ Branch 1 taken 34484 times.
|
69306 | } else if (ha_alter_info->virtual_column_add_count > 0 && |
| 6331 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 1 times.
|
338 | ha_alter_info->virtual_column_drop_count == 0) { |
| 6332 | /* if there is ongoing drop virtual column, then we disallow | ||
| 6333 | inplace add index on newly added virtual column, so it does | ||
| 6334 | not need to come in here to rebuild template with add_v. | ||
| 6335 | Please also see the assertion in innodb_v_adjust_idx_col() */ | ||
| 6336 | |||
| 6337 |
1/2✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
|
336 | s_templ = ut::new_withkey<dict_vcol_templ_t>(UT_NEW_THIS_FILE_PSI_KEY); |
| 6338 | |||
| 6339 | add_v = static_cast<dict_add_v_col_t *>( | ||
| 6340 |
1/2✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
|
336 | mem_heap_alloc(ctx->heap, sizeof *add_v)); |
| 6341 | 336 | add_v->n_v_col = ha_alter_info->virtual_column_add_count; | |
| 6342 | 336 | add_v->v_col = ctx->add_vcol; | |
| 6343 | 336 | add_v->v_col_name = ctx->add_vcol_name; | |
| 6344 | |||
| 6345 | 336 | s_templ->vtempl = nullptr; | |
| 6346 | |||
| 6347 |
1/2✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
|
336 | innobase_build_v_templ(altered_table, ctx->new_table, s_templ, add_v, false, |
| 6348 | nullptr); | ||
| 6349 | 336 | old_templ = ctx->new_table->vc_templ; | |
| 6350 | 336 | ctx->new_table->vc_templ = s_templ; | |
| 6351 | } | ||
| 6352 | |||
| 6353 | /* Drop virtual column without rebuild will keep dict table | ||
| 6354 | unchanged, we use old table to evaluate virtual column value | ||
| 6355 | in innobase_get_computed_value(). */ | ||
| 6356 |
6/6✓ Branch 0 taken 5175 times.
✓ Branch 1 taken 30301 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 5169 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 35470 times.
|
70952 | if (!ctx->need_rebuild() && ha_alter_info->virtual_column_drop_count > 0) { |
| 6357 | 12 | eval_table = table; | |
| 6358 | } | ||
| 6359 | |||
| 6360 | 281701 | auto clean_up = [&](dberr_t err) -> bool { | |
| 6361 |
3/4✓ Branch 0 taken 2958 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31679 times.
✓ Branch 3 taken 839 times.
|
35476 | DEBUG_SYNC_C("alter_table_update_log"); |
| 6362 | |||
| 6363 |
16/16✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2947 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 2571 times.
✓ Branch 5 taken 376 times.
✓ Branch 6 taken 2571 times.
✓ Branch 7 taken 387 times.
✓ Branch 8 taken 32421 times.
✓ Branch 9 taken 97 times.
✓ Branch 10 taken 31590 times.
✓ Branch 11 taken 831 times.
✓ Branch 12 taken 27409 times.
✓ Branch 13 taken 4181 times.
✓ Branch 14 taken 27409 times.
✓ Branch 15 taken 5109 times.
|
35476 | if (err == DB_SUCCESS && ctx->online && ctx->need_rebuild()) { |
| 6364 |
3/4✓ Branch 0 taken 2571 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26570 times.
✓ Branch 3 taken 839 times.
|
29980 | DEBUG_SYNC_C("row_log_table_apply1_before"); |
| 6365 | 29980 | err = row_log_table_apply(ctx->thr, m_prebuilt->table, altered_table, | |
| 6366 | ctx->m_stage); | ||
| 6367 | } | ||
| 6368 | |||
| 6369 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 2958 times.
✓ Branch 2 taken 991 times.
✓ Branch 3 taken 31527 times.
|
35476 | if (s_templ) { |
| 6370 |
4/16✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 168 times.
✓ Branch 9 taken 823 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 168 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 991 times.
|
991 | ut_ad(ctx->need_rebuild() || |
| 6371 | ha_alter_info->virtual_column_add_count > 0 || rebuild_templ); | ||
| 6372 | 991 | dict_free_vc_templ(s_templ); | |
| 6373 | 991 | ut::delete_(s_templ); | |
| 6374 | |||
| 6375 | 991 | ctx->new_table->vc_templ = old_templ; | |
| 6376 | } | ||
| 6377 | |||
| 6378 |
3/4✓ Branch 0 taken 2958 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31679 times.
✓ Branch 3 taken 839 times.
|
35476 | DEBUG_SYNC_C("inplace_after_index_build"); |
| 6379 | |||
| 6380 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 2958 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 32517 times.
|
35476 | DBUG_EXECUTE_IF("create_index_fail", err = DB_DUPLICATE_KEY; |
| 6381 | m_prebuilt->trx->error_key_num = ULINT_UNDEFINED;); | ||
| 6382 | |||
| 6383 | /* After an error, remove all those index definitions | ||
| 6384 | from the dictionary which were defined. */ | ||
| 6385 | |||
| 6386 |
6/10✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32411 times.
✓ Branch 6 taken 37 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 68 times.
|
35476 | switch (err) { |
| 6387 | 35367 | case DB_SUCCESS: | |
| 6388 | 35367 | return success(); | |
| 6389 | 39 | case DB_DUPLICATE_KEY: { | |
| 6390 | 39 | KEY *dup_key{}; | |
| 6391 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 1 times.
|
39 | if (m_prebuilt->trx->error_key_num == ULINT_UNDEFINED || |
| 6392 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
38 | ha_alter_info->key_count == 0) { |
| 6393 | /* This should be the hidden index on | ||
| 6394 | FTS_DOC_ID, or there is no PRIMARY KEY in the | ||
| 6395 | table. Either way, we should be seeing and | ||
| 6396 | reporting a bogus duplicate key error. */ | ||
| 6397 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 14 times.
|
38 | } else if (m_prebuilt->trx->error_key_num == 0) { |
| 6398 | 23 | dup_key = | |
| 6399 | 23 | &ha_alter_info->key_info_buffer[m_prebuilt->trx->error_key_num]; | |
| 6400 | } else { | ||
| 6401 | /* Check if there is generated cluster index column */ | ||
| 6402 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12 times.
|
15 | if (ctx->num_to_add_index > ha_alter_info->key_count) { |
| 6403 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | assert(m_prebuilt->trx->error_key_num <= ha_alter_info->key_count); |
| 6404 | 2 | dup_key = | |
| 6405 | &ha_alter_info | ||
| 6406 | 2 | ->key_info_buffer[m_prebuilt->trx->error_key_num - 1]; | |
| 6407 | } else { | ||
| 6408 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
13 | assert(m_prebuilt->trx->error_key_num < ha_alter_info->key_count); |
| 6409 | 13 | dup_key = | |
| 6410 | 13 | &ha_alter_info->key_info_buffer[m_prebuilt->trx->error_key_num]; | |
| 6411 | } | ||
| 6412 | } | ||
| 6413 | 39 | print_keydup_error(altered_table, dup_key, MYF(0), | |
| 6414 | 39 | table_share->table_name.str); | |
| 6415 | 39 | break; | |
| 6416 | } | ||
| 6417 | 2 | case DB_ONLINE_LOG_TOO_BIG: | |
| 6418 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | assert(ctx->online); |
| 6419 | 2 | my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), | |
| 6420 | 2 | get_error_key_name(m_prebuilt->trx->error_key_num, | |
| 6421 | 2 | ha_alter_info, m_prebuilt->table)); | |
| 6422 | 2 | break; | |
| 6423 | ✗ | case DB_INDEX_CORRUPT: | |
| 6424 | ✗ | my_error(ER_INDEX_CORRUPT, MYF(0), | |
| 6425 | ✗ | get_error_key_name(m_prebuilt->trx->error_key_num, | |
| 6426 | ✗ | ha_alter_info, m_prebuilt->table)); | |
| 6427 | ✗ | break; | |
| 6428 | 68 | default: | |
| 6429 | 68 | my_error_innodb(err, table_share->table_name.str, | |
| 6430 | 68 | m_prebuilt->table->flags); | |
| 6431 | } | ||
| 6432 | |||
| 6433 | /* prebuilt->table->n_ref_count can be anything here, given | ||
| 6434 | that we hold at most a shared lock on the table. */ | ||
| 6435 | 109 | m_prebuilt->trx->error_index = nullptr; | |
| 6436 | 109 | ctx->trx->error_state = DB_SUCCESS; | |
| 6437 | |||
| 6438 | 109 | return true; | |
| 6439 | }; | ||
| 6440 | |||
| 6441 | /* Read the clustered index of the table and build | ||
| 6442 | indexes based on this information using temporary | ||
| 6443 | files and merge sort. */ | ||
| 6444 |
4/6✓ Branch 0 taken 35476 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 35474 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
70952 | DBUG_EXECUTE_IF("innodb_OOM_inplace_alter", |
| 6445 | return clean_up(DB_OUT_OF_MEMORY);); | ||
| 6446 | |||
| 6447 | 70948 | const auto trx = m_prebuilt->trx; | |
| 6448 | 70948 | const auto old_isolation_level = trx->isolation_level; | |
| 6449 | |||
| 6450 |
2/2✓ Branch 0 taken 34602 times.
✓ Branch 1 taken 872 times.
|
70948 | if (ctx->online && |
| 6451 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 34549 times.
|
69204 | trx->isolation_level != trx_t::isolation_level_t::REPEATABLE_READ) { |
| 6452 | /* We must scan the index at an isolation level >= READ COMMITTED, because | ||
| 6453 | a dirty read will see half written blob references. | ||
| 6454 | |||
| 6455 | ** Perform a REPEATABLE READ. | ||
| 6456 | When rebuilding the table online, row_log_table_apply() must not see | ||
| 6457 | a newer state of the table when applying the log. This is mainly to | ||
| 6458 | prevent false duplicate key errors, because the log will identify records | ||
| 6459 | by the PRIMARY KEY, and also to prevent unsafe BLOB access. | ||
| 6460 | |||
| 6461 | When creating a secondary index online, this table scan must not see | ||
| 6462 | records that have only been inserted to the clustered index, but have | ||
| 6463 | not been written to the online_log of index[]. If we performed | ||
| 6464 | READ UNCOMMITTED, it could happen that the ADD INDEX reaches | ||
| 6465 | ONLINE_INDEX_COMPLETE state between the time the DML thread has updated | ||
| 6466 | the clustered index but has not yet accessed secondary index. */ | ||
| 6467 | |||
| 6468 | 106 | trx->isolation_level = trx_t::isolation_level_t::REPEATABLE_READ; | |
| 6469 | } | ||
| 6470 | |||
| 6471 | 212844 | ddl::Context ddl(trx, m_prebuilt->table, ctx->new_table, ctx->online, | |
| 6472 | ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index, | ||
| 6473 | 70948 | altered_table, ctx->add_cols, ctx->col_map, ctx->add_autoinc, | |
| 6474 | 70948 | ctx->sequence, ctx->skip_pk_sort, ctx->m_stage, add_v, | |
| 6475 |
1/2✓ Branch 0 taken 35474 times.
✗ Branch 1 not taken.
|
70948 | eval_table, thd_ddl_buffer_size(m_prebuilt->trx->mysql_thd), |
| 6476 | 70948 | thd_ddl_threads(m_prebuilt->trx->mysql_thd)); | |
| 6477 | |||
| 6478 |
1/2✓ Branch 0 taken 35474 times.
✗ Branch 1 not taken.
|
70948 | const auto err = clean_up(ddl.build()); |
| 6479 | |||
| 6480 | 70948 | trx->isolation_level = old_isolation_level; | |
| 6481 | |||
| 6482 | 70948 | return err; | |
| 6483 | 112052 | } | |
| 6484 | |||
| 6485 | /** Free the modification log for online table rebuild. | ||
| 6486 | @param table table that was being rebuilt online */ | ||
| 6487 | 30265 | static void innobase_online_rebuild_log_free(dict_table_t *table) { | |
| 6488 | 30265 | dict_index_t *clust_index = table->first_index(); | |
| 6489 | |||
| 6490 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30265 times.
|
30265 | ut_ad(dict_sys_mutex_own()); |
| 6491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30265 times.
|
30265 | ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); |
| 6492 | |||
| 6493 | 30265 | rw_lock_x_lock(&clust_index->lock, UT_LOCATION_HERE); | |
| 6494 | |||
| 6495 |
2/2✓ Branch 0 taken 29977 times.
✓ Branch 1 taken 288 times.
|
30265 | if (clust_index->online_log) { |
| 6496 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29977 times.
|
29977 | ut_ad(dict_index_get_online_status(clust_index) == ONLINE_INDEX_CREATION); |
| 6497 | 29977 | clust_index->online_status = ONLINE_INDEX_COMPLETE; | |
| 6498 | 29977 | row_log_free(clust_index->online_log); | |
| 6499 |
2/2✓ Branch 0 taken 29138 times.
✓ Branch 1 taken 839 times.
|
29977 | DEBUG_SYNC_C("innodb_online_rebuild_log_free_aborted"); |
| 6500 | } | ||
| 6501 | |||
| 6502 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30265 times.
|
30265 | assert(dict_index_get_online_status(clust_index) == ONLINE_INDEX_COMPLETE); |
| 6503 | 30265 | rw_lock_x_unlock(&clust_index->lock); | |
| 6504 | 30265 | } | |
| 6505 | |||
| 6506 | /** Rollback a secondary index creation, drop the indexes with | ||
| 6507 | temparary index prefix | ||
| 6508 | @param user_table InnoDB table | ||
| 6509 | @param table the TABLE | ||
| 6510 | @param locked true=table locked, false=may need to do a lazy drop | ||
| 6511 | @param trx the transaction | ||
| 6512 | */ | ||
| 6513 | 82 | static void innobase_rollback_sec_index(dict_table_t *user_table, | |
| 6514 | const TABLE *table, bool locked, | ||
| 6515 | trx_t *trx) { | ||
| 6516 | 82 | ddl::drop_indexes(trx, user_table, locked); | |
| 6517 | |||
| 6518 | /* Free the table->fts only if there is no FTS_DOC_ID | ||
| 6519 | in the table */ | ||
| 6520 | 168 | if (user_table->fts && | |
| 6521 |
4/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 82 times.
|
82 | !DICT_TF2_FLAG_IS_SET(user_table, DICT_TF2_FTS_HAS_DOC_ID) && |
| 6522 | ✗ | !innobase_fulltext_exist(table)) { | |
| 6523 | ✗ | fts_free(user_table); | |
| 6524 | } | ||
| 6525 | 82 | } | |
| 6526 | |||
| 6527 | /** Roll back the changes made during prepare_inplace_alter_table() | ||
| 6528 | and inplace_alter_table() inside the storage engine. Note that the | ||
| 6529 | allowed level of concurrency during this operation will be the same as | ||
| 6530 | for inplace_alter_table() and thus might be higher than during | ||
| 6531 | prepare_inplace_alter_table(). (E.g concurrent writes were blocked | ||
| 6532 | during prepare, but might not be during commit). | ||
| 6533 | |||
| 6534 | @param[in] ha_alter_info Data used during in-place alter. | ||
| 6535 | @param[in] table the TABLE | ||
| 6536 | @param[in,out] prebuilt the prebuilt struct | ||
| 6537 | @retval true Failure | ||
| 6538 | @retval false Success | ||
| 6539 | */ | ||
| 6540 | 393 | [[nodiscard]] inline bool rollback_inplace_alter_table( | |
| 6541 | const Alter_inplace_info *ha_alter_info, const TABLE *table, | ||
| 6542 | row_prebuilt_t *prebuilt) { | ||
| 6543 | 393 | bool fail = false; | |
| 6544 | |||
| 6545 | 393 | ha_innobase_inplace_ctx *ctx = | |
| 6546 | static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | ||
| 6547 | |||
| 6548 |
1/2✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
|
393 | DBUG_TRACE; |
| 6549 | |||
| 6550 |
4/4✓ Branch 0 taken 134 times.
✓ Branch 1 taken 259 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 132 times.
|
393 | if (!ctx || !ctx->trx) { |
| 6551 | /* If we have not started a transaction yet, | ||
| 6552 | (almost) nothing has been or needs to be done. */ | ||
| 6553 | 261 | goto func_exit; | |
| 6554 | } | ||
| 6555 | |||
| 6556 |
1/2✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
|
132 | row_mysql_lock_data_dictionary(ctx->trx, UT_LOCATION_HERE); |
| 6557 | |||
| 6558 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 75 times.
|
132 | if (ctx->need_rebuild()) { |
| 6559 | /* The table could have been closed in commit phase */ | ||
| 6560 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 4 times.
|
57 | if (ctx->new_table != nullptr) { |
| 6561 | 53 | dberr_t err = DB_SUCCESS; | |
| 6562 | 53 | uint32_t flags = ctx->new_table->flags; | |
| 6563 | /* DML threads can access ctx->new_table via the | ||
| 6564 | online rebuild log. Free it first. */ | ||
| 6565 |
1/2✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
|
53 | innobase_online_rebuild_log_free(prebuilt->table); |
| 6566 | |||
| 6567 |
1/2✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
|
53 | dict_table_close(ctx->new_table, true, false); |
| 6568 | |||
| 6569 |
1/2✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
|
53 | switch (err) { |
| 6570 | 53 | case DB_SUCCESS: | |
| 6571 | 53 | break; | |
| 6572 | ✗ | default: | |
| 6573 | ✗ | my_error_innodb(err, table->s->table_name.str, flags); | |
| 6574 | ✗ | fail = true; | |
| 6575 | } | ||
| 6576 | } | ||
| 6577 | } else { | ||
| 6578 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
|
75 | assert(!(ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX)); |
| 6579 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
|
75 | assert(ctx->new_table == prebuilt->table); |
| 6580 | |||
| 6581 |
1/2✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
|
75 | innobase_rollback_sec_index(prebuilt->table, table, false, ctx->trx); |
| 6582 | } | ||
| 6583 | |||
| 6584 |
1/2✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
|
132 | row_mysql_unlock_data_dictionary(ctx->trx); |
| 6585 | |||
| 6586 | 393 | func_exit: | |
| 6587 | #ifdef UNIV_DEBUG | ||
| 6588 |
1/2✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
|
393 | dict_index_t *clust_index = prebuilt->table->first_index(); |
| 6589 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 393 times.
|
393 | assert(!clust_index->online_log); |
| 6590 |
2/4✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 393 times.
|
393 | assert(dict_index_get_online_status(clust_index) == ONLINE_INDEX_COMPLETE); |
| 6591 | #endif /* UNIV_DEBUG */ | ||
| 6592 | |||
| 6593 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 259 times.
|
393 | if (ctx) { |
| 6594 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
|
134 | assert(ctx->prebuilt == prebuilt); |
| 6595 | |||
| 6596 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 132 times.
|
134 | if (ctx->num_to_add_fk) { |
| 6597 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (ulint i = 0; i < ctx->num_to_add_fk; i++) { |
| 6598 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | dict_foreign_free(ctx->add_fk[i]); |
| 6599 | } | ||
| 6600 | } | ||
| 6601 | |||
| 6602 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 130 times.
|
134 | if (ctx->num_to_drop_index) { |
| 6603 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | row_mysql_lock_data_dictionary(prebuilt->trx, UT_LOCATION_HERE); |
| 6604 | |||
| 6605 | /* Clear the to_be_dropped flags | ||
| 6606 | in the data dictionary cache. | ||
| 6607 | The flags may already have been cleared, | ||
| 6608 | in case an error was detected in | ||
| 6609 | commit_inplace_alter_table(). */ | ||
| 6610 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | for (ulint i = 0; i < ctx->num_to_drop_index; i++) { |
| 6611 | 4 | dict_index_t *index = ctx->drop_index[i]; | |
| 6612 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | assert(index->is_committed()); |
| 6613 | 4 | index->to_be_dropped = 0; | |
| 6614 | } | ||
| 6615 | |||
| 6616 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | row_mysql_unlock_data_dictionary(prebuilt->trx); |
| 6617 | } | ||
| 6618 | } | ||
| 6619 | |||
| 6620 |
1/2✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
|
393 | reset_column_ord_part(prebuilt->table); |
| 6621 | |||
| 6622 | /* Do not commit/rollback prebuilt->trx, assume mysql will | ||
| 6623 | rollback it */ | ||
| 6624 | |||
| 6625 | 393 | MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); | |
| 6626 | 393 | return fail; | |
| 6627 | 393 | } | |
| 6628 | |||
| 6629 | /** Rename or enlarge columns in the data dictionary cache | ||
| 6630 | as part of commit_cache_norebuild(). | ||
| 6631 | @param ha_alter_info Data used during in-place alter. | ||
| 6632 | @param table the TABLE | ||
| 6633 | @param user_table InnoDB table that was being altered */ | ||
| 6634 | 17016 | static void innobase_rename_or_enlarge_columns_cache( | |
| 6635 | Alter_inplace_info *ha_alter_info, const TABLE *table, | ||
| 6636 | dict_table_t *user_table) { | ||
| 6637 |
2/2✓ Branch 0 taken 16886 times.
✓ Branch 1 taken 130 times.
|
17016 | if (!(ha_alter_info->handler_flags & |
| 6638 | (Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | | ||
| 6639 | Alter_inplace_info::ALTER_COLUMN_NAME))) { | ||
| 6640 | 16886 | return; | |
| 6641 | } | ||
| 6642 | |||
| 6643 | List_iterator_fast<Create_field> cf_it( | ||
| 6644 |
1/2✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
|
130 | ha_alter_info->alter_info->create_list); |
| 6645 | 130 | uint i = 0; | |
| 6646 | 130 | ulint num_v = 0; | |
| 6647 | 130 | ulint unsigned_flag = 0; | |
| 6648 | |||
| 6649 |
2/2✓ Branch 0 taken 385 times.
✓ Branch 1 taken 130 times.
|
515 | for (Field **fp = table->field; *fp; fp++, i++) { |
| 6650 |
3/4✓ Branch 0 taken 49 times.
✓ Branch 1 taken 336 times.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
|
385 | bool is_virtual = innobase_is_v_fld(*fp); |
| 6651 | |||
| 6652 | 385 | cf_it.rewind(); | |
| 6653 |
1/2✓ Branch 0 taken 1420 times.
✗ Branch 1 not taken.
|
1420 | while (const Create_field *cf = cf_it++) { |
| 6654 |
2/2✓ Branch 0 taken 1035 times.
✓ Branch 1 taken 385 times.
|
1420 | if (cf->field != *fp) { |
| 6655 | 1035 | continue; | |
| 6656 | } | ||
| 6657 | |||
| 6658 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 336 times.
|
385 | ulint col_n = is_virtual ? num_v : i - num_v; |
| 6659 | |||
| 6660 |
3/4✓ Branch 0 taken 385 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 295 times.
|
385 | if ((*fp)->is_equal(cf) == IS_EQUAL_PACK_LENGTH) { |
| 6661 | dict_col_t *col; | ||
| 6662 | |||
| 6663 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 89 times.
|
90 | if (is_virtual) { |
| 6664 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | col = &dict_table_get_nth_v_col(user_table, col_n)->m_col; |
| 6665 | } else { | ||
| 6666 |
1/2✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
|
89 | col = user_table->get_col(col_n); |
| 6667 | } | ||
| 6668 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | col->len = cf->max_display_width_in_bytes(); |
| 6669 | |||
| 6670 | ulint innodb_data_type = | ||
| 6671 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | get_innobase_type_from_mysql_type(&unsigned_flag, cf->field); |
| 6672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | ut_ad(innodb_data_type != DATA_MISSING); |
| 6673 | |||
| 6674 |
5/6✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 46 times.
|
178 | if (dtype_is_non_binary_string_type(innodb_data_type, col->prtype) && |
| 6675 |
3/4✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 44 times.
|
88 | (*fp)->charset()->number != cf->charset->number) { |
| 6676 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | ulint old_charset = (*fp)->charset()->number; |
| 6677 | 44 | ulint new_charset = cf->charset->number; | |
| 6678 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | ut_ad(dtype_get_charset_coll(col->prtype) == old_charset); |
| 6679 | |||
| 6680 | 44 | col->prtype = | |
| 6681 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | dtype_form_prtype(col->prtype - (old_charset << 16), new_charset); |
| 6682 | ulint mbminlen; | ||
| 6683 | ulint mbmaxlen; | ||
| 6684 | |||
| 6685 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | dtype_get_mblen(col->mtype, col->prtype, &mbminlen, &mbmaxlen); |
| 6686 | 44 | col->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen); | |
| 6687 | } | ||
| 6688 | } | ||
| 6689 | |||
| 6690 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 342 times.
|
385 | if ((*fp)->is_flag_set(FIELD_IS_RENAMED)) { |
| 6691 | 43 | dict_mem_table_col_rename(user_table, col_n, cf->field->field_name, | |
| 6692 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | cf->field_name, is_virtual); |
| 6693 | } | ||
| 6694 | |||
| 6695 | 385 | break; | |
| 6696 | 1035 | } | |
| 6697 | |||
| 6698 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 336 times.
|
385 | if (is_virtual) { |
| 6699 | 49 | num_v++; | |
| 6700 | } | ||
| 6701 | } | ||
| 6702 | } | ||
| 6703 | /** Get the auto-increment value of the table on commit. | ||
| 6704 | @param[in] ha_alter_info Data used during in-place alter | ||
| 6705 | @param[in,out] ctx In-place ALTER TABLE context | ||
| 6706 | return autoinc value in ctx->max_autoinc | ||
| 6707 | @param[in] altered_table MySQL table that is being altered | ||
| 6708 | @param[in] old_table MySQL table as it is before the ALTER operation | ||
| 6709 | @retval true Failure | ||
| 6710 | @retval false Success*/ | ||
| 6711 | 47303 | [[nodiscard]] static bool commit_get_autoinc(Alter_inplace_info *ha_alter_info, | |
| 6712 | ha_innobase_inplace_ctx *ctx, | ||
| 6713 | const TABLE *altered_table, | ||
| 6714 | const TABLE *old_table) { | ||
| 6715 |
1/2✓ Branch 0 taken 47303 times.
✗ Branch 1 not taken.
|
47303 | DBUG_TRACE; |
| 6716 | |||
| 6717 |
2/2✓ Branch 0 taken 42866 times.
✓ Branch 1 taken 4437 times.
|
47303 | if (!altered_table->found_next_number_field) { |
| 6718 | /* There is no AUTO_INCREMENT column in the table | ||
| 6719 | after the ALTER operation. */ | ||
| 6720 | 42866 | ctx->max_autoinc = 0; | |
| 6721 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 4396 times.
|
4437 | } else if (ctx->add_autoinc != ULINT_UNDEFINED) { |
| 6722 | /* An AUTO_INCREMENT column was added. Get the last | ||
| 6723 | value from the sequence, which may be based on a | ||
| 6724 | supplied AUTO_INCREMENT value. */ | ||
| 6725 | 41 | ctx->max_autoinc = ctx->sequence.last(); | |
| 6726 |
2/2✓ Branch 0 taken 1076 times.
✓ Branch 1 taken 3320 times.
|
4396 | } else if ((ha_alter_info->handler_flags & |
| 6727 | 1076 | Alter_inplace_info::CHANGE_CREATE_OPTION) && | |
| 6728 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 932 times.
|
1076 | (ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) { |
| 6729 | /* Check if the table is discarded */ | ||
| 6730 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
|
144 | if (dict_table_is_discarded(ctx->old_table)) { |
| 6731 | ✗ | return true; | |
| 6732 | } | ||
| 6733 | |||
| 6734 | /* An AUTO_INCREMENT value was supplied, but the table was not | ||
| 6735 | rebuilt. Get the user-supplied value or the last value from the | ||
| 6736 | sequence. */ | ||
| 6737 | uint64_t max_value_table; | ||
| 6738 | |||
| 6739 | 144 | Field *autoinc_field = old_table->found_next_number_field; | |
| 6740 | |||
| 6741 | 144 | ctx->max_autoinc = ha_alter_info->create_info->auto_increment_value; | |
| 6742 | |||
| 6743 |
1/2✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
|
144 | dict_table_autoinc_lock(ctx->old_table); |
| 6744 | |||
| 6745 | 144 | max_value_table = ctx->old_table->autoinc_persisted; | |
| 6746 | |||
| 6747 | /* We still have to search the index here when we want to | ||
| 6748 | set the AUTO_INCREMENT value to a smaller or equal one. | ||
| 6749 | |||
| 6750 | Here is an example: | ||
| 6751 | Let's say we have a table t1 with one AUTOINC column, existing | ||
| 6752 | rows (1), (2), (100), (200), (1000), after following SQLs: | ||
| 6753 | DELETE FROM t1 WHERE a > 200; | ||
| 6754 | ALTER TABLE t1 AUTO_INCREMENT = 150; | ||
| 6755 | we expect the next value allocated from 201, but not 150. | ||
| 6756 | |||
| 6757 | We could only search the tree to know current max counter | ||
| 6758 | in the table and compare. */ | ||
| 6759 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 133 times.
|
144 | if (ctx->max_autoinc <= max_value_table) { |
| 6760 | dberr_t err; | ||
| 6761 | dict_index_t *index; | ||
| 6762 | |||
| 6763 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | index = dict_table_get_index_on_first_col(ctx->old_table, |
| 6764 | 11 | autoinc_field->field_index()); | |
| 6765 | |||
| 6766 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | err = row_search_max_autoinc(index, autoinc_field->field_name, |
| 6767 | &max_value_table); | ||
| 6768 | |||
| 6769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (err != DB_SUCCESS) { |
| 6770 | ✗ | ctx->max_autoinc = 0; | |
| 6771 | ✗ | ut_d(ut_error); | |
| 6772 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | } else if (ctx->max_autoinc <= max_value_table) { |
| 6773 | ulonglong col_max_value; | ||
| 6774 | ulonglong offset; | ||
| 6775 | |||
| 6776 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | col_max_value = autoinc_field->get_max_int_value(); |
| 6777 | 5 | offset = ctx->prebuilt->autoinc_offset; | |
| 6778 | 5 | ctx->max_autoinc = | |
| 6779 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | innobase_next_autoinc(max_value_table, 1, 1, offset, col_max_value); |
| 6780 | } | ||
| 6781 | } | ||
| 6782 | |||
| 6783 |
1/2✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
|
144 | dict_table_autoinc_unlock(ctx->old_table); |
| 6784 | 144 | } else { | |
| 6785 | /* An AUTO_INCREMENT value was not specified. | ||
| 6786 | Read the old counter value from the table. */ | ||
| 6787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4252 times.
|
4252 | ut_ad(old_table->found_next_number_field); |
| 6788 |
1/2✓ Branch 0 taken 4252 times.
✗ Branch 1 not taken.
|
4252 | dict_table_autoinc_lock(ctx->old_table); |
| 6789 | 4252 | ctx->max_autoinc = ctx->old_table->autoinc; | |
| 6790 |
1/2✓ Branch 0 taken 4252 times.
✗ Branch 1 not taken.
|
4252 | dict_table_autoinc_unlock(ctx->old_table); |
| 6791 | } | ||
| 6792 | |||
| 6793 | 47303 | return false; | |
| 6794 | 47303 | } | |
| 6795 | |||
| 6796 | /** Add or drop foreign key constraints to the data dictionary tables, | ||
| 6797 | but do not touch the data dictionary cache. | ||
| 6798 | @param ctx In-place ALTER TABLE context | ||
| 6799 | @param trx Data dictionary transaction | ||
| 6800 | @param table_name Table name in MySQL | ||
| 6801 | @retval true Failure | ||
| 6802 | @retval false Success | ||
| 6803 | */ | ||
| 6804 | 47302 | [[nodiscard]] static bool innobase_update_foreign_try( | |
| 6805 | ha_innobase_inplace_ctx *ctx, trx_t *trx, const char *table_name) { | ||
| 6806 | ulint foreign_id; | ||
| 6807 | ulint i; | ||
| 6808 | |||
| 6809 |
1/2✓ Branch 0 taken 47302 times.
✗ Branch 1 not taken.
|
47302 | DBUG_TRACE; |
| 6810 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47302 times.
|
47302 | assert(ctx); |
| 6811 | |||
| 6812 |
1/2✓ Branch 0 taken 47302 times.
✗ Branch 1 not taken.
|
47302 | foreign_id = dict_table_get_highest_foreign_id(ctx->new_table); |
| 6813 | |||
| 6814 | 47302 | foreign_id++; | |
| 6815 | |||
| 6816 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 47300 times.
|
47396 | for (i = 0; i < ctx->num_to_add_fk; i++) { |
| 6817 | 96 | dict_foreign_t *fk = ctx->add_fk[i]; | |
| 6818 | |||
| 6819 |
4/6✓ Branch 0 taken 8 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
|
96 | ut_ad(fk->foreign_table == ctx->new_table || |
| 6820 | fk->foreign_table == ctx->old_table); | ||
| 6821 | |||
| 6822 | 192 | dberr_t error = dict_create_add_foreign_id(&foreign_id, | |
| 6823 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | ctx->old_table->name.m_name, fk); |
| 6824 | |||
| 6825 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (error != DB_SUCCESS) { |
| 6826 | ✗ | my_error(ER_TOO_LONG_IDENT, MYF(0), fk->id); | |
| 6827 | ✗ | return true; | |
| 6828 | } | ||
| 6829 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 71 times.
|
96 | if (!fk->foreign_index) { |
| 6830 | 50 | fk->foreign_index = dict_foreign_find_index( | |
| 6831 | 25 | ctx->new_table, ctx->col_names, fk->foreign_col_names, fk->n_fields, | |
| 6832 | 25 | fk->referenced_index, true, | |
| 6833 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | fk->type & (DICT_FOREIGN_ON_DELETE_SET_NULL | |
| 6834 | DICT_FOREIGN_ON_UPDATE_SET_NULL)); | ||
| 6835 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (!fk->foreign_index) { |
| 6836 | ✗ | my_error(ER_FK_INCORRECT_OPTION, MYF(0), table_name, fk->id); | |
| 6837 | ✗ | return true; | |
| 6838 | } | ||
| 6839 | } | ||
| 6840 | |||
| 6841 | /* During upgrade, inserts into SYS_* should be avoided. */ | ||
| 6842 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | if (!srv_is_upgrade_mode) { |
| 6843 |
3/4✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 94 times.
|
96 | DBUG_EXECUTE_IF("innodb_test_cannot_add_fk_system", error = DB_ERROR;); |
| 6844 | |||
| 6845 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
|
96 | if (error != DB_SUCCESS) { |
| 6846 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_FAIL_ADD_SYSTEM, MYF(0), fk->id); |
| 6847 | 2 | return true; | |
| 6848 | } | ||
| 6849 | } | ||
| 6850 | } | ||
| 6851 |
4/6✓ Branch 0 taken 47300 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 47299 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
47300 | DBUG_EXECUTE_IF("ib_drop_foreign_error", |
| 6852 | my_error_innodb(DB_OUT_OF_FILE_SPACE, table_name, 0); | ||
| 6853 | trx->error_state = DB_SUCCESS; return true;); | ||
| 6854 | 47299 | return false; | |
| 6855 | 47302 | } | |
| 6856 | |||
| 6857 | /** Update the foreign key constraint definitions in the data dictionary cache | ||
| 6858 | after the changes to data dictionary tables were committed. | ||
| 6859 | @param[in,out] ctx In-place ALTER TABLE context | ||
| 6860 | @param[in] user_thd MySQL connection | ||
| 6861 | @param[in,out] dd_table dd table instance | ||
| 6862 | @return InnoDB error code (should always be DB_SUCCESS) */ | ||
| 6863 | 17032 | [[nodiscard]] static dberr_t innobase_update_foreign_cache( | |
| 6864 | ha_innobase_inplace_ctx *ctx, THD *user_thd, dd::Table *dd_table) { | ||
| 6865 | dict_table_t *user_table; | ||
| 6866 | 17032 | dberr_t err = DB_SUCCESS; | |
| 6867 | |||
| 6868 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | DBUG_TRACE; |
| 6869 | |||
| 6870 |
2/4✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17032 times.
|
17032 | ut_ad(dict_sys_mutex_own()); |
| 6871 | |||
| 6872 | 17032 | user_table = ctx->old_table; | |
| 6873 | |||
| 6874 | /* Discard the added foreign keys, because we will | ||
| 6875 | load them from the data dictionary. */ | ||
| 6876 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 17032 times.
|
17119 | for (ulint i = 0; i < ctx->num_to_add_fk; i++) { |
| 6877 | 87 | dict_foreign_t *fk = ctx->add_fk[i]; | |
| 6878 |
1/2✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
|
87 | dict_foreign_free(fk); |
| 6879 | } | ||
| 6880 | |||
| 6881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17032 times.
|
17032 | if (ctx->need_rebuild()) { |
| 6882 | /* The rebuilt table is already using the renamed | ||
| 6883 | column names. No need to pass col_names or to drop | ||
| 6884 | constraints from the data dictionary cache. */ | ||
| 6885 | ✗ | assert(!ctx->col_names); | |
| 6886 | ✗ | assert(user_table->foreign_set.empty()); | |
| 6887 | ✗ | assert(user_table->referenced_set.empty()); | |
| 6888 | ✗ | user_table = ctx->new_table; | |
| 6889 | } else { | ||
| 6890 | /* Drop the foreign key constraints if the | ||
| 6891 | table was not rebuilt. If the table is rebuilt, | ||
| 6892 | there would not be any foreign key contraints for | ||
| 6893 | it yet in the data dictionary cache. */ | ||
| 6894 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 17032 times.
|
17070 | for (ulint i = 0; i < ctx->num_to_drop_fk; i++) { |
| 6895 | 38 | dict_foreign_t *fk = ctx->drop_fk[i]; | |
| 6896 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | dict_foreign_remove_from_cache(fk); |
| 6897 | } | ||
| 6898 | } | ||
| 6899 | |||
| 6900 | /* Load the old or added foreign keys from the data dictionary | ||
| 6901 | and prevent the table from being evicted from the data | ||
| 6902 | dictionary cache (work around the lack of WL#6049). */ | ||
| 6903 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | dict_names_t fk_tables; |
| 6904 | |||
| 6905 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | dd::cache::Dictionary_client *client = dd::get_dd_client(user_thd); |
| 6906 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | dd::cache::Dictionary_client::Auto_releaser releaser(client); |
| 6907 | err = | ||
| 6908 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | dd_table_load_fk(client, user_table->name.m_name, ctx->col_names, |
| 6909 | user_table, dd_table, user_thd, true, true, &fk_tables); | ||
| 6910 | |||
| 6911 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17032 times.
|
17032 | if (err == DB_CANNOT_ADD_CONSTRAINT) { |
| 6912 | ✗ | fk_tables.clear(); | |
| 6913 | |||
| 6914 | /* It is possible there are existing foreign key are | ||
| 6915 | loaded with "foreign_key checks" off, | ||
| 6916 | so let's retry the loading with charset_check is off */ | ||
| 6917 | ✗ | err = dd_table_load_fk(client, user_table->name.m_name, ctx->col_names, | |
| 6918 | user_table, dd_table, user_thd, true, false, | ||
| 6919 | &fk_tables); | ||
| 6920 | |||
| 6921 | /* The load with "charset_check" off is successful, warn | ||
| 6922 | the user that the foreign key has loaded with mis-matched | ||
| 6923 | charset */ | ||
| 6924 | ✗ | if (err == DB_SUCCESS) { | |
| 6925 | ✗ | push_warning_printf(user_thd, Sql_condition::SL_WARNING, ER_ALTER_INFO, | |
| 6926 | "Foreign key constraints for table '%s'" | ||
| 6927 | " are loaded with charset check off", | ||
| 6928 | user_table->name.m_name); | ||
| 6929 | } | ||
| 6930 | } | ||
| 6931 | |||
| 6932 | /* For complete loading of foreign keys, all associated tables must | ||
| 6933 | also be loaded. */ | ||
| 6934 | |||
| 6935 |
3/6✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17032 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 17032 times.
|
17032 | while (err == DB_SUCCESS && !fk_tables.empty()) { |
| 6936 | ✗ | dict_sys_mutex_exit(); | |
| 6937 | ✗ | dd::cache::Dictionary_client *client = dd::get_dd_client(user_thd); | |
| 6938 | |||
| 6939 | ✗ | dd::cache::Dictionary_client::Auto_releaser releaser(client); | |
| 6940 | |||
| 6941 | ✗ | dd_open_fk_tables(fk_tables, false, user_thd); | |
| 6942 | ✗ | dict_sys_mutex_enter(); | |
| 6943 | } | ||
| 6944 | |||
| 6945 | 17032 | return err; | |
| 6946 | 17032 | } | |
| 6947 | |||
| 6948 | /** Discard the foreign key cache if anyone is affected by current | ||
| 6949 | column rename. This is only used for rebuild case. | ||
| 6950 | @param[in] ha_alter_info data used during in-place alter | ||
| 6951 | @param[in] mysql_table MySQL TABLE object | ||
| 6952 | @param[in,out] old_table InnoDB table object for old table */ | ||
| 6953 | 14 | static void innobase_rename_col_discard_foreign( | |
| 6954 | Alter_inplace_info *ha_alter_info, const TABLE *mysql_table, | ||
| 6955 | dict_table_t *old_table) { | ||
| 6956 | List_iterator_fast<Create_field> cf_it( | ||
| 6957 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | ha_alter_info->alter_info->create_list); |
| 6958 | |||
| 6959 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | ut_ad(ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NAME); |
| 6960 | |||
| 6961 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 14 times.
|
61 | for (Field **fp = mysql_table->field; *fp; fp++) { |
| 6962 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 17 times.
|
47 | if (!(*fp)->is_flag_set(FIELD_IS_RENAMED)) { |
| 6963 | 30 | continue; | |
| 6964 | } | ||
| 6965 | |||
| 6966 | 17 | cf_it.rewind(); | |
| 6967 | |||
| 6968 | 17 | ut_d(bool processed = false;) | |
| 6969 | |||
| 6970 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 17 times.
|
81 | while (Create_field *cf = cf_it++) { |
| 6971 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 17 times.
|
64 | if (cf->field != *fp) { |
| 6972 | 47 | continue; | |
| 6973 | } | ||
| 6974 | |||
| 6975 | /* Now cf->field->field_name is the old name, check the foreign key | ||
| 6976 | information to see any one gets affected by this rename, and discard | ||
| 6977 | them from cache */ | ||
| 6978 | |||
| 6979 | 17 | std::list<dict_foreign_t *> fk_evict; | |
| 6980 | |||
| 6981 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
|
26 | for (auto fk : old_table->foreign_set) { |
| 6982 | 9 | dict_foreign_t *foreign = fk; | |
| 6983 | |||
| 6984 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
|
15 | for (unsigned i = 0; i < foreign->n_fields; i++) { |
| 6985 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | if (strcmp(foreign->foreign_col_names[i], cf->field->field_name) != |
| 6986 | 0) { | ||
| 6987 | 6 | continue; | |
| 6988 | } | ||
| 6989 | |||
| 6990 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fk_evict.push_back(foreign); |
| 6991 | 3 | break; | |
| 6992 | } | ||
| 6993 | } | ||
| 6994 | |||
| 6995 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
|
18 | for (auto fk : old_table->referenced_set) { |
| 6996 | 1 | dict_foreign_t *foreign = fk; | |
| 6997 | |||
| 6998 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (unsigned i = 0; i < foreign->n_fields; i++) { |
| 6999 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (strcmp(foreign->referenced_col_names[i], cf->field->field_name) != |
| 7000 | 0) { | ||
| 7001 | ✗ | continue; | |
| 7002 | } | ||
| 7003 | |||
| 7004 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fk_evict.push_back(foreign); |
| 7005 | 1 | break; | |
| 7006 | } | ||
| 7007 | } | ||
| 7008 | |||
| 7009 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | std::for_each(fk_evict.begin(), fk_evict.end(), |
| 7010 | dict_foreign_remove_from_cache); | ||
| 7011 | |||
| 7012 | 17 | ut_d(processed = true;) | |
| 7013 | 81 | } | |
| 7014 | |||
| 7015 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | ut_ad(processed); |
| 7016 | } | ||
| 7017 | 14 | } | |
| 7018 | |||
| 7019 | /** Commit the changes made during prepare_inplace_alter_table() | ||
| 7020 | and inplace_alter_table() inside the data dictionary tables, | ||
| 7021 | when rebuilding the table. | ||
| 7022 | @param ha_alter_info Data used during in-place alter | ||
| 7023 | @param ctx In-place ALTER TABLE context | ||
| 7024 | @param altered_table MySQL table that is being altered | ||
| 7025 | @param old_table MySQL table as it is before the ALTER operation | ||
| 7026 | @param trx Data dictionary transaction | ||
| 7027 | @param table_name Table name in MySQL | ||
| 7028 | @retval true Failure | ||
| 7029 | @retval false Success | ||
| 7030 | */ | ||
| 7031 | 30252 | [[nodiscard]] inline bool commit_try_rebuild(Alter_inplace_info *ha_alter_info, | |
| 7032 | ha_innobase_inplace_ctx *ctx, | ||
| 7033 | TABLE *altered_table, | ||
| 7034 | const TABLE *old_table, trx_t *trx, | ||
| 7035 | const char *table_name) { | ||
| 7036 | 30252 | dict_table_t *rebuilt_table = ctx->new_table; | |
| 7037 | 30252 | dict_table_t *user_table = ctx->old_table; | |
| 7038 | |||
| 7039 |
1/2✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
|
30252 | DBUG_TRACE; |
| 7040 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30252 times.
|
30252 | assert(ctx->need_rebuild()); |
| 7041 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30252 times.
|
30252 | assert(trx->dict_operation_lock_mode == RW_X_LATCH); |
| 7042 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 30252 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
30252 | assert( |
| 7043 | !(ha_alter_info->handler_flags & Alter_inplace_info::DROP_FOREIGN_KEY) || | ||
| 7044 | ctx->num_to_drop_fk > 0); | ||
| 7045 | |||
| 7046 |
3/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39652 times.
✓ Branch 3 taken 30252 times.
|
69904 | for (dict_index_t *index = rebuilt_table->first_index(); index; |
| 7047 |
1/2✓ Branch 0 taken 39652 times.
✗ Branch 1 not taken.
|
39652 | index = index->next()) { |
| 7048 |
2/4✓ Branch 0 taken 39652 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39652 times.
|
39652 | assert(dict_index_get_online_status(index) == ONLINE_INDEX_COMPLETE); |
| 7049 |
2/4✓ Branch 0 taken 39652 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39652 times.
|
39652 | assert(index->is_committed()); |
| 7050 |
2/4✓ Branch 0 taken 39652 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39652 times.
|
39652 | if (index->is_corrupted()) { |
| 7051 | ✗ | my_error(ER_INDEX_CORRUPT, MYF(0), index->name()); | |
| 7052 | ✗ | return true; | |
| 7053 | } | ||
| 7054 | } | ||
| 7055 | |||
| 7056 |
3/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30251 times.
|
30252 | if (innobase_update_foreign_try(ctx, trx, table_name)) { |
| 7057 | 1 | return true; | |
| 7058 | } | ||
| 7059 | |||
| 7060 | 30251 | dberr_t error = DB_SUCCESS; | |
| 7061 | |||
| 7062 | /* Clear the to_be_dropped flag in the data dictionary cache | ||
| 7063 | of user_table. */ | ||
| 7064 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 30251 times.
|
30321 | for (ulint i = 0; i < ctx->num_to_drop_index; i++) { |
| 7065 | 70 | dict_index_t *index = ctx->drop_index[i]; | |
| 7066 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | assert(index->table == user_table); |
| 7067 |
2/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
|
70 | assert(index->is_committed()); |
| 7068 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | assert(index->to_be_dropped); |
| 7069 | 70 | index->to_be_dropped = 0; | |
| 7070 | } | ||
| 7071 | |||
| 7072 | /* We copied the table. Any indexes that were requested to be | ||
| 7073 | dropped were not created in the copy of the table. Apply any | ||
| 7074 | last bit of the rebuild log and then rename the tables. */ | ||
| 7075 | |||
| 7076 |
2/2✓ Branch 0 taken 29966 times.
✓ Branch 1 taken 285 times.
|
30251 | if (ctx->online) { |
| 7077 |
3/4✓ Branch 0 taken 29127 times.
✓ Branch 1 taken 839 times.
✓ Branch 2 taken 29127 times.
✗ Branch 3 not taken.
|
29966 | DEBUG_SYNC_C("row_log_table_apply2_before"); |
| 7078 | |||
| 7079 | 29966 | dict_vcol_templ_t *s_templ = nullptr; | |
| 7080 | |||
| 7081 |
2/2✓ Branch 0 taken 820 times.
✓ Branch 1 taken 29146 times.
|
29966 | if (ctx->new_table->n_v_cols > 0) { |
| 7082 |
1/2✓ Branch 0 taken 820 times.
✗ Branch 1 not taken.
|
820 | s_templ = ut::new_withkey<dict_vcol_templ_t>(UT_NEW_THIS_FILE_PSI_KEY); |
| 7083 | 820 | s_templ->vtempl = nullptr; | |
| 7084 | |||
| 7085 |
1/2✓ Branch 0 taken 820 times.
✗ Branch 1 not taken.
|
820 | innobase_build_v_templ(altered_table, ctx->new_table, s_templ, nullptr, |
| 7086 | true, nullptr); | ||
| 7087 | 820 | ctx->new_table->vc_templ = s_templ; | |
| 7088 | } | ||
| 7089 | |||
| 7090 | 59932 | error = row_log_table_apply( | |
| 7091 | ctx->thr, user_table, altered_table, | ||
| 7092 |
1/2✓ Branch 0 taken 29966 times.
✗ Branch 1 not taken.
|
29966 | static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx) |
| 7093 | ->m_stage); | ||
| 7094 | |||
| 7095 |
2/2✓ Branch 0 taken 820 times.
✓ Branch 1 taken 29146 times.
|
29966 | if (s_templ) { |
| 7096 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 820 times.
|
820 | ut_ad(ctx->need_rebuild()); |
| 7097 |
1/2✓ Branch 0 taken 820 times.
✗ Branch 1 not taken.
|
820 | dict_free_vc_templ(s_templ); |
| 7098 | 820 | ut::delete_(s_templ); | |
| 7099 | 820 | ctx->new_table->vc_templ = nullptr; | |
| 7100 | } | ||
| 7101 | |||
| 7102 |
1/2✓ Branch 0 taken 29966 times.
✗ Branch 1 not taken.
|
29966 | ulint err_key = thr_get_trx(ctx->thr)->error_key_num; |
| 7103 | |||
| 7104 |
1/5✓ Branch 0 taken 29966 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
29966 | switch (error) { |
| 7105 | KEY *dup_key; | ||
| 7106 | 29966 | case DB_SUCCESS: | |
| 7107 | 29966 | break; | |
| 7108 | ✗ | case DB_DUPLICATE_KEY: | |
| 7109 | ✗ | if (err_key == ULINT_UNDEFINED) { | |
| 7110 | /* This should be the hidden index on | ||
| 7111 | FTS_DOC_ID. */ | ||
| 7112 | ✗ | dup_key = nullptr; | |
| 7113 | } else { | ||
| 7114 | /* Check if there is generated cluster index column */ | ||
| 7115 | ✗ | if (ctx->num_to_add_index > ha_alter_info->key_count) { | |
| 7116 | ✗ | assert(err_key <= ha_alter_info->key_count); | |
| 7117 | ✗ | dup_key = &ha_alter_info->key_info_buffer[err_key - 1]; | |
| 7118 | } else { | ||
| 7119 | ✗ | assert(err_key < ha_alter_info->key_count); | |
| 7120 | ✗ | dup_key = &ha_alter_info->key_info_buffer[err_key]; | |
| 7121 | } | ||
| 7122 | } | ||
| 7123 | ✗ | print_keydup_error(altered_table, dup_key, MYF(0), | |
| 7124 | ✗ | old_table->s->table_name.str); | |
| 7125 | ✗ | return true; | |
| 7126 | ✗ | case DB_ONLINE_LOG_TOO_BIG: | |
| 7127 | ✗ | my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), | |
| 7128 | get_error_key_name(err_key, ha_alter_info, rebuilt_table)); | ||
| 7129 | ✗ | return true; | |
| 7130 | ✗ | case DB_INDEX_CORRUPT: | |
| 7131 | ✗ | my_error(ER_INDEX_CORRUPT, MYF(0), | |
| 7132 | get_error_key_name(err_key, ha_alter_info, rebuilt_table)); | ||
| 7133 | ✗ | return true; | |
| 7134 | ✗ | default: | |
| 7135 | ✗ | my_error_innodb(error, table_name, user_table->flags); | |
| 7136 | ✗ | return true; | |
| 7137 | } | ||
| 7138 | } | ||
| 7139 |
2/6✓ Branch 0 taken 30251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30251 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30251 | DBUG_EXECUTE_IF("ib_rename_column_error", |
| 7140 | my_error_innodb(DB_OUT_OF_FILE_SPACE, table_name, 0); | ||
| 7141 | trx->error_state = DB_SUCCESS; trx->op_info = ""; | ||
| 7142 | return true;); | ||
| 7143 |
2/6✓ Branch 0 taken 30251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30251 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30251 | DBUG_EXECUTE_IF("ib_ddl_crash_before_rename", DBUG_SUICIDE();); |
| 7144 | |||
| 7145 | /* The new table must inherit the flag from the | ||
| 7146 | "parent" table. */ | ||
| 7147 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30247 times.
|
30251 | if (dict_table_is_discarded(user_table)) { |
| 7148 | 4 | rebuilt_table->ibd_file_missing = true; | |
| 7149 | 4 | rebuilt_table->flags2 |= DICT_TF2_DISCARDED; | |
| 7150 | } | ||
| 7151 | /* We must be still holding a table handle. */ | ||
| 7152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30251 times.
|
30251 | assert(user_table->get_ref_count() >= 1); |
| 7153 | |||
| 7154 |
2/6✓ Branch 0 taken 30251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30251 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30251 | DBUG_EXECUTE_IF("ib_ddl_crash_after_rename", DBUG_SUICIDE();); |
| 7155 |
2/4✓ Branch 0 taken 30251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30251 times.
|
30251 | DBUG_EXECUTE_IF("ib_rebuild_cannot_rename", error = DB_ERROR;); |
| 7156 | |||
| 7157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30251 times.
|
30251 | if (user_table->get_ref_count() > 1) { |
| 7158 | /* This should only occur when an innodb_memcached | ||
| 7159 | connection with innodb_api_enable_mdl=off was started | ||
| 7160 | before commit_inplace_alter_table() locked the data | ||
| 7161 | dictionary. We must roll back the ALTER TABLE, because | ||
| 7162 | we cannot drop a table while it is being used. */ | ||
| 7163 | |||
| 7164 | /* Normally, n_ref_count must be 1, because purge | ||
| 7165 | cannot be executing on this very table as we are | ||
| 7166 | holding MDL lock. */ | ||
| 7167 | ✗ | my_error(ER_TABLE_REFERENCED, MYF(0)); | |
| 7168 | ✗ | return true; | |
| 7169 | } | ||
| 7170 | |||
| 7171 |
1/4✓ Branch 0 taken 30251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
30251 | switch (error) { |
| 7172 | 30251 | case DB_SUCCESS: | |
| 7173 | 30251 | return false; | |
| 7174 | ✗ | case DB_TABLESPACE_EXISTS: | |
| 7175 | ✗ | ut_a(rebuilt_table->get_ref_count() == 1); | |
| 7176 | ✗ | my_error(ER_TABLESPACE_EXISTS, MYF(0), ctx->tmp_name); | |
| 7177 | ✗ | return true; | |
| 7178 | ✗ | case DB_DUPLICATE_KEY: | |
| 7179 | ✗ | ut_a(rebuilt_table->get_ref_count() == 1); | |
| 7180 | ✗ | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), ctx->tmp_name); | |
| 7181 | ✗ | return true; | |
| 7182 | ✗ | default: | |
| 7183 | ✗ | my_error_innodb(error, table_name, user_table->flags); | |
| 7184 | ✗ | return true; | |
| 7185 | } | ||
| 7186 | 30252 | } | |
| 7187 | |||
| 7188 | /** Apply the changes made during commit_try_rebuild(), | ||
| 7189 | to the data dictionary cache and the file system. | ||
| 7190 | @param ctx In-place ALTER TABLE context */ | ||
| 7191 | 30208 | inline void commit_cache_rebuild(ha_innobase_inplace_ctx *ctx) { | |
| 7192 | dberr_t error; | ||
| 7193 | |||
| 7194 |
1/2✓ Branch 0 taken 30208 times.
✗ Branch 1 not taken.
|
30208 | DBUG_TRACE; |
| 7195 |
3/4✓ Branch 0 taken 29369 times.
✓ Branch 1 taken 839 times.
✓ Branch 2 taken 29369 times.
✗ Branch 3 not taken.
|
30208 | DEBUG_SYNC_C("commit_cache_rebuild"); |
| 7196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30208 times.
|
30208 | assert(ctx->need_rebuild()); |
| 7197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30208 times.
|
30208 | assert(dict_table_is_discarded(ctx->old_table) == |
| 7198 | dict_table_is_discarded(ctx->new_table)); | ||
| 7199 | |||
| 7200 | const char *old_name = | ||
| 7201 |
1/2✓ Branch 0 taken 30208 times.
✗ Branch 1 not taken.
|
30208 | mem_heap_strdup(ctx->heap, ctx->old_table->name.m_name); |
| 7202 | |||
| 7203 | /* We already committed and redo logged the renames, | ||
| 7204 | so this must succeed. */ | ||
| 7205 |
1/2✓ Branch 0 taken 30184 times.
✗ Branch 1 not taken.
|
30208 | error = dict_table_rename_in_cache(ctx->old_table, ctx->tmp_name, false); |
| 7206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30184 times.
|
30184 | ut_a(error == DB_SUCCESS); |
| 7207 | |||
| 7208 |
3/4✓ Branch 0 taken 29345 times.
✓ Branch 1 taken 839 times.
✓ Branch 2 taken 29345 times.
✗ Branch 3 not taken.
|
30184 | DEBUG_SYNC_C("commit_cache_rebuild_middle"); |
| 7209 | |||
| 7210 |
1/2✓ Branch 0 taken 30160 times.
✗ Branch 1 not taken.
|
30184 | error = dict_table_rename_in_cache(ctx->new_table, old_name, false); |
| 7211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30160 times.
|
30160 | ut_a(error == DB_SUCCESS); |
| 7212 | 30160 | } | |
| 7213 | |||
| 7214 | /** Set of column numbers */ | ||
| 7215 | typedef std::set<ulint, std::less<ulint>, ut::allocator<ulint>> col_set; | ||
| 7216 | |||
| 7217 | /** Store the column number of the columns in a list belonging | ||
| 7218 | to indexes which are not being dropped. | ||
| 7219 | @param[in] ctx In-place ALTER TABLE context | ||
| 7220 | @param[in, out] drop_col_list list which will be set, containing columns | ||
| 7221 | which is part of index being dropped | ||
| 7222 | @param[in, out] drop_v_col_list list which will be set, containing | ||
| 7223 | virtual columns which is part of index | ||
| 7224 | being dropped */ | ||
| 7225 | 17032 | static void get_col_list_to_be_dropped(const ha_innobase_inplace_ctx *ctx, | |
| 7226 | col_set &drop_col_list, | ||
| 7227 | col_set &drop_v_col_list) { | ||
| 7228 |
2/2✓ Branch 0 taken 1182 times.
✓ Branch 1 taken 17032 times.
|
18214 | for (ulint index_count = 0; index_count < ctx->num_to_drop_index; |
| 7229 | index_count++) { | ||
| 7230 | 1182 | const dict_index_t *index = ctx->drop_index[index_count]; | |
| 7231 | |||
| 7232 |
2/2✓ Branch 0 taken 1316 times.
✓ Branch 1 taken 1182 times.
|
2498 | for (ulint col = 0; col < index->n_user_defined_cols; col++) { |
| 7233 | 1316 | const dict_col_t *idx_col = index->get_col(col); | |
| 7234 | |||
| 7235 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 1200 times.
|
1316 | if (idx_col->is_virtual()) { |
| 7236 | 116 | const dict_v_col_t *v_col = | |
| 7237 | reinterpret_cast<const dict_v_col_t *>(idx_col); | ||
| 7238 | 116 | drop_v_col_list.insert(v_col->v_pos); | |
| 7239 | |||
| 7240 | } else { | ||
| 7241 |
1/2✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
|
1200 | ulint col_no = dict_col_get_no(idx_col); |
| 7242 |
1/2✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
|
1200 | drop_col_list.insert(col_no); |
| 7243 | } | ||
| 7244 | } | ||
| 7245 | } | ||
| 7246 | 17032 | } | |
| 7247 | |||
| 7248 | /** Commit the changes made during prepare_inplace_alter_table() and | ||
| 7249 | inplace_alter_table() inside the data dictionary tables, when not rebuilding | ||
| 7250 | the table. | ||
| 7251 | @param[in] ha_alter_info Data used during in-place alter | ||
| 7252 | @param[in] ctx In-place ALTER TABLE context | ||
| 7253 | @param[in] trx Data dictionary transaction | ||
| 7254 | @param[in] table_name Table name in MySQL | ||
| 7255 | @retval true Failure | ||
| 7256 | @retval false Success */ | ||
| 7257 | 17051 | [[nodiscard]] inline bool commit_try_norebuild( | |
| 7258 | Alter_inplace_info *ha_alter_info, ha_innobase_inplace_ctx *ctx, trx_t *trx, | ||
| 7259 | const char *table_name) { | ||
| 7260 |
1/2✓ Branch 0 taken 17051 times.
✗ Branch 1 not taken.
|
17051 | DBUG_TRACE; |
| 7261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17051 times.
|
17051 | assert(!ctx->need_rebuild()); |
| 7262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17051 times.
|
17051 | assert(trx->dict_operation_lock_mode == RW_X_LATCH); |
| 7263 |
3/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 17013 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
|
17051 | assert( |
| 7264 | !(ha_alter_info->handler_flags & Alter_inplace_info::DROP_FOREIGN_KEY) || | ||
| 7265 | ctx->num_to_drop_fk > 0); | ||
| 7266 | |||
| 7267 |
2/2✓ Branch 0 taken 5322 times.
✓ Branch 1 taken 17050 times.
|
22372 | for (ulint i = 0; i < ctx->num_to_add_index; i++) { |
| 7268 | 5322 | dict_index_t *index = ctx->add_index[i]; | |
| 7269 |
2/4✓ Branch 0 taken 5322 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5322 times.
|
5322 | assert(dict_index_get_online_status(index) == ONLINE_INDEX_COMPLETE); |
| 7270 |
2/4✓ Branch 0 taken 5322 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5322 times.
|
5322 | assert(!index->is_committed()); |
| 7271 |
3/4✓ Branch 0 taken 5322 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5321 times.
|
5322 | if (index->is_corrupted()) { |
| 7272 | /* Report a duplicate key | ||
| 7273 | error for the index that was | ||
| 7274 | flagged corrupted, most likely | ||
| 7275 | because a duplicate value was | ||
| 7276 | inserted (directly or by | ||
| 7277 | rollback) after | ||
| 7278 | ha_innobase::inplace_alter_table() | ||
| 7279 | completed. | ||
| 7280 | TODO: report this as a corruption | ||
| 7281 | with a detailed reason once | ||
| 7282 | WL#6379 has been implemented. */ | ||
| 7283 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_DUP_UNKNOWN_IN_INDEX, MYF(0), index->name()); |
| 7284 | 1 | return true; | |
| 7285 | } | ||
| 7286 | } | ||
| 7287 | |||
| 7288 |
3/4✓ Branch 0 taken 17050 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 17048 times.
|
17050 | if (innobase_update_foreign_try(ctx, trx, table_name)) { |
| 7289 | 2 | return true; | |
| 7290 | } | ||
| 7291 | |||
| 7292 |
4/6✓ Branch 0 taken 17048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 17046 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
17048 | DBUG_EXECUTE_IF("ib_rename_column_error", |
| 7293 | my_error_innodb(DB_OUT_OF_FILE_SPACE, table_name, 0); | ||
| 7294 | trx->error_state = DB_SUCCESS; trx->op_info = ""; | ||
| 7295 | return true;); | ||
| 7296 | |||
| 7297 |
4/6✓ Branch 0 taken 17046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17045 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
17046 | DBUG_EXECUTE_IF("ib_resize_column_error", |
| 7298 | my_error_innodb(DB_OUT_OF_FILE_SPACE, table_name, 0); | ||
| 7299 | trx->error_state = DB_SUCCESS; trx->op_info = ""; | ||
| 7300 | return true;); | ||
| 7301 | |||
| 7302 |
4/6✓ Branch 0 taken 17045 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17044 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
17045 | DBUG_EXECUTE_IF( |
| 7303 | "ib_rename_index_fail1", my_error_innodb(DB_DEADLOCK, table_name, 0); | ||
| 7304 | trx->error_state = DB_SUCCESS; trx->op_info = ""; return true;); | ||
| 7305 | |||
| 7306 | 17044 | return false; | |
| 7307 | 17051 | } | |
| 7308 | |||
| 7309 | /** Commit the changes to the data dictionary cache | ||
| 7310 | after a successful commit_try_norebuild() call. | ||
| 7311 | @param ctx In-place ALTER TABLE context | ||
| 7312 | @param trx Data dictionary transaction object | ||
| 7313 | (will be started and committed) | ||
| 7314 | @return whether all replacements were found for dropped indexes */ | ||
| 7315 | 17032 | [[nodiscard]] inline bool commit_cache_norebuild(ha_innobase_inplace_ctx *ctx, | |
| 7316 | trx_t *trx) { | ||
| 7317 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | DBUG_TRACE; |
| 7318 | |||
| 7319 | 17032 | bool found = true; | |
| 7320 | |||
| 7321 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17032 times.
|
17032 | assert(!ctx->need_rebuild()); |
| 7322 | |||
| 7323 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | col_set drop_list; |
| 7324 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | col_set v_drop_list; |
| 7325 | 17032 | col_set::const_iterator col_it; | |
| 7326 | |||
| 7327 | /* Check if the column, part of an index to be dropped is part of any | ||
| 7328 | other index which is not being dropped. If not, then set the ord_part | ||
| 7329 | of the column to 0. Here the columns are collected first. */ | ||
| 7330 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | get_col_list_to_be_dropped(ctx, drop_list, v_drop_list); |
| 7331 | |||
| 7332 |
2/2✓ Branch 0 taken 5308 times.
✓ Branch 1 taken 17032 times.
|
22340 | for (ulint i = 0; i < ctx->num_to_add_index; i++) { |
| 7333 | 5308 | dict_index_t *index = ctx->add_index[i]; | |
| 7334 |
2/4✓ Branch 0 taken 5308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5308 times.
|
5308 | assert(dict_index_get_online_status(index) == ONLINE_INDEX_COMPLETE); |
| 7335 |
2/4✓ Branch 0 taken 5308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5308 times.
|
5308 | assert(!index->is_committed()); |
| 7336 |
1/2✓ Branch 0 taken 5308 times.
✗ Branch 1 not taken.
|
5308 | index->set_committed(true); |
| 7337 | } | ||
| 7338 | |||
| 7339 |
2/2✓ Branch 0 taken 1138 times.
✓ Branch 1 taken 15894 times.
|
17032 | if (ctx->num_to_drop_index) { |
| 7340 | /* Drop indexes in data dictionary cache and write | ||
| 7341 | DDL log for them */ | ||
| 7342 |
2/2✓ Branch 0 taken 1182 times.
✓ Branch 1 taken 1138 times.
|
2320 | for (ulint i = 0; i < ctx->num_to_drop_index; i++) { |
| 7343 | 1182 | dict_index_t *index = ctx->drop_index[i]; | |
| 7344 |
2/4✓ Branch 0 taken 1182 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1182 times.
|
1182 | assert(index->is_committed()); |
| 7345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1182 times.
|
1182 | assert(index->table == ctx->new_table); |
| 7346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1182 times.
|
1182 | assert(index->to_be_dropped); |
| 7347 | |||
| 7348 | /* Replace the indexes in foreign key | ||
| 7349 | constraints if needed. */ | ||
| 7350 |
2/4✓ Branch 0 taken 1182 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1182 times.
|
1182 | if (!dict_foreign_replace_index(index->table, ctx->col_names, index)) { |
| 7351 | ✗ | found = false; | |
| 7352 | } | ||
| 7353 | } | ||
| 7354 | |||
| 7355 |
2/2✓ Branch 0 taken 1180 times.
✓ Branch 1 taken 1122 times.
|
2302 | for (ulint i = 0; i < ctx->num_to_drop_index; i++) { |
| 7356 | 1180 | dict_index_t *index = ctx->drop_index[i]; | |
| 7357 |
2/4✓ Branch 0 taken 1180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1180 times.
|
1180 | assert(index->is_committed()); |
| 7358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1180 times.
|
1180 | assert(index->table == ctx->new_table); |
| 7359 | |||
| 7360 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 1066 times.
|
1180 | if (index->type & DICT_FTS) { |
| 7361 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
114 | assert(index->type == DICT_FTS || index->is_corrupted()); |
| 7362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
|
114 | assert(index->table->fts); |
| 7363 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | ctx->fts_drop_aux_vec = new aux_name_vec_t; |
| 7364 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | fts_drop_index(index->table, index, trx, ctx->fts_drop_aux_vec); |
| 7365 | } | ||
| 7366 | |||
| 7367 | /* It is a single table tablespace and the .ibd file is | ||
| 7368 | missing if root is FIL_NULL, do nothing. */ | ||
| 7369 |
2/2✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 117 times.
|
1180 | if (index->page != FIL_NULL) { |
| 7370 |
1/2✓ Branch 0 taken 1063 times.
✗ Branch 1 not taken.
|
1063 | dict_sys_mutex_exit(); |
| 7371 |
1/2✓ Branch 0 taken 1047 times.
✗ Branch 1 not taken.
|
1063 | ut_d(dberr_t err =) log_ddl->write_free_tree_log(trx, index, true); |
| 7372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1047 times.
|
1047 | ut_ad(err == DB_SUCCESS); |
| 7373 |
1/2✓ Branch 0 taken 1047 times.
✗ Branch 1 not taken.
|
1047 | dict_sys_mutex_enter(); |
| 7374 | } | ||
| 7375 | |||
| 7376 |
1/2✓ Branch 0 taken 1164 times.
✗ Branch 1 not taken.
|
1164 | btr_drop_ahi_for_index(index); |
| 7377 |
1/2✓ Branch 0 taken 1164 times.
✗ Branch 1 not taken.
|
1164 | dict_index_remove_from_cache(index->table, index); |
| 7378 | } | ||
| 7379 | } | ||
| 7380 | |||
| 7381 | /* Update the ord_part after index dropped, to get accurate values */ | ||
| 7382 |
2/2✓ Branch 0 taken 1169 times.
✓ Branch 1 taken 17016 times.
|
18185 | for (col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) { |
| 7383 |
3/4✓ Branch 0 taken 1169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 917 times.
✓ Branch 3 taken 252 times.
|
1169 | if (!check_col_exists_in_indexes(ctx->new_table, *col_it, false)) { |
| 7384 | 917 | ctx->new_table->cols[*col_it].ord_part = 0; | |
| 7385 | } | ||
| 7386 | } | ||
| 7387 | |||
| 7388 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 17016 times.
|
17127 | for (col_it = v_drop_list.begin(); col_it != v_drop_list.end(); ++col_it) { |
| 7389 |
3/4✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✓ Branch 3 taken 9 times.
|
111 | if (!check_col_exists_in_indexes(ctx->new_table, *col_it, true)) { |
| 7390 | 102 | ctx->new_table->v_cols[*col_it].m_col.ord_part = 0; | |
| 7391 | } | ||
| 7392 | } | ||
| 7393 | |||
| 7394 | 17016 | ctx->new_table->fts_doc_id_index = | |
| 7395 | 17016 | ctx->new_table->fts | |
| 7396 |
3/4✓ Branch 0 taken 468 times.
✓ Branch 1 taken 16548 times.
✓ Branch 2 taken 468 times.
✗ Branch 3 not taken.
|
17016 | ? dict_table_get_index_on_name(ctx->new_table, FTS_DOC_ID_INDEX_NAME) |
| 7397 | : nullptr; | ||
| 7398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17016 times.
|
17016 | assert((ctx->new_table->fts == nullptr) == |
| 7399 | (ctx->new_table->fts_doc_id_index == nullptr)); | ||
| 7400 | |||
| 7401 | 17016 | return found; | |
| 7402 | 17016 | } | |
| 7403 | |||
| 7404 | /** Adjust the persistent statistics after non-rebuilding ALTER TABLE. | ||
| 7405 | Remove statistics for dropped indexes, add statistics for created indexes | ||
| 7406 | and rename statistics for renamed indexes. | ||
| 7407 | @param ha_alter_info Data used during in-place alter | ||
| 7408 | @param ctx In-place ALTER TABLE context | ||
| 7409 | @param table_name Table name in MySQL | ||
| 7410 | @param thd MySQL connection | ||
| 7411 | */ | ||
| 7412 | 16623 | static void alter_stats_norebuild(Alter_inplace_info *ha_alter_info, | |
| 7413 | ha_innobase_inplace_ctx *ctx, | ||
| 7414 | const char *table_name, THD *thd) { | ||
| 7415 | ulint i; | ||
| 7416 | |||
| 7417 |
1/2✓ Branch 0 taken 16623 times.
✗ Branch 1 not taken.
|
16623 | DBUG_TRACE; |
| 7418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16623 times.
|
16623 | assert(!ctx->need_rebuild()); |
| 7419 | |||
| 7420 |
3/4✓ Branch 0 taken 16623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4706 times.
✓ Branch 3 taken 11917 times.
|
16623 | if (!dict_stats_is_persistent_enabled(ctx->new_table)) { |
| 7421 | 4706 | return; | |
| 7422 | } | ||
| 7423 | |||
| 7424 | /* Delete corresponding rows from the stats table. We do this | ||
| 7425 | in a separate transaction from trx, because lock waits are not | ||
| 7426 | allowed in a data dictionary transaction. (Lock waits are possible | ||
| 7427 | on the statistics table, because it is directly accessible by users, | ||
| 7428 | not covered by the dict_operation_lock.) | ||
| 7429 | |||
| 7430 | Because the data dictionary changes were already committed, orphaned | ||
| 7431 | rows may be left in the statistics table if the system crashes. | ||
| 7432 | |||
| 7433 | FIXME: each change to the statistics tables is being committed in a | ||
| 7434 | separate transaction, meaning that the operation is not atomic | ||
| 7435 | |||
| 7436 | FIXME: This will not drop the (unused) statistics for | ||
| 7437 | FTS_DOC_ID_INDEX if it was a hidden index, dropped together | ||
| 7438 | with the last renamining FULLTEXT index. */ | ||
| 7439 |
2/2✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 11917 times.
|
12949 | for (i = 0; i < ha_alter_info->index_drop_count; i++) { |
| 7440 | 1032 | const KEY *key = ha_alter_info->index_drop_buffer[i]; | |
| 7441 | |||
| 7442 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 920 times.
|
1032 | if (key->flags & HA_FULLTEXT) { |
| 7443 | /* There are no index cardinality | ||
| 7444 | statistics for FULLTEXT indexes. */ | ||
| 7445 | 112 | continue; | |
| 7446 | } | ||
| 7447 | |||
| 7448 | char errstr[ERROR_STR_LENGTH]; | ||
| 7449 | |||
| 7450 |
1/2✓ Branch 0 taken 920 times.
✗ Branch 1 not taken.
|
920 | if (dict_stats_drop_index(ctx->new_table->name.m_name, key->name, errstr, |
| 7451 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 919 times.
|
920 | sizeof errstr) != DB_SUCCESS) { |
| 7452 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | push_warning(thd, Sql_condition::SL_WARNING, ER_LOCK_WAIT_TIMEOUT, |
| 7453 | errstr); | ||
| 7454 | } | ||
| 7455 | } | ||
| 7456 | |||
| 7457 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 11917 times.
|
11995 | for (i = 0; i < ha_alter_info->index_rename_count; i++) { |
| 7458 | 78 | KEY_PAIR *pair = &ha_alter_info->index_rename_buffer[i]; | |
| 7459 | dberr_t err; | ||
| 7460 | |||
| 7461 | 156 | err = dict_stats_rename_index(ctx->new_table, pair->old_key->name, | |
| 7462 |
1/2✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
|
78 | pair->new_key->name); |
| 7463 | |||
| 7464 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (err != DB_SUCCESS) { |
| 7465 | ✗ | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_ERROR_ON_RENAME, | |
| 7466 | "Error renaming an index of table '%s'" | ||
| 7467 | " from '%s' to '%s' in InnoDB persistent" | ||
| 7468 | " statistics storage: %s", | ||
| 7469 | ✗ | table_name, pair->old_key->name, pair->new_key->name, | |
| 7470 | ut_strerr(err)); | ||
| 7471 | } | ||
| 7472 | } | ||
| 7473 | |||
| 7474 |
2/2✓ Branch 0 taken 5076 times.
✓ Branch 1 taken 11917 times.
|
16993 | for (i = 0; i < ctx->num_to_add_index; i++) { |
| 7475 | 5076 | dict_index_t *index = ctx->add_index[i]; | |
| 7476 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5076 times.
|
5076 | assert(index->table == ctx->new_table); |
| 7477 | |||
| 7478 |
2/2✓ Branch 0 taken 4749 times.
✓ Branch 1 taken 327 times.
|
5076 | if (!(index->type & DICT_FTS)) { |
| 7479 |
1/2✓ Branch 0 taken 4749 times.
✗ Branch 1 not taken.
|
4749 | dict_stats_init(ctx->new_table); |
| 7480 |
1/2✓ Branch 0 taken 4749 times.
✗ Branch 1 not taken.
|
4749 | dict_stats_update_for_index(index); |
| 7481 | } | ||
| 7482 | } | ||
| 7483 |
2/2✓ Branch 0 taken 11917 times.
✓ Branch 1 taken 4706 times.
|
16623 | } |
| 7484 | |||
| 7485 | /** Adjust the persistent statistics after rebuilding ALTER TABLE. | ||
| 7486 | Remove statistics for dropped indexes, add statistics for created indexes | ||
| 7487 | and rename statistics for renamed indexes. | ||
| 7488 | @param table InnoDB table that was rebuilt by ALTER TABLE | ||
| 7489 | @param table_name Table name in MySQL | ||
| 7490 | @param thd MySQL connection | ||
| 7491 | */ | ||
| 7492 | 30071 | static void alter_stats_rebuild(dict_table_t *table, const char *table_name, | |
| 7493 | THD *thd) { | ||
| 7494 |
1/2✓ Branch 0 taken 30071 times.
✗ Branch 1 not taken.
|
30071 | DBUG_TRACE; |
| 7495 |
2/6✓ Branch 0 taken 30071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30071 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30071 | DBUG_EXECUTE_IF("ib_ddl_crash_before_rename", DBUG_SUICIDE();); |
| 7496 | |||
| 7497 |
4/4✓ Branch 0 taken 30067 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 16004 times.
✓ Branch 3 taken 14067 times.
|
60138 | if (dict_table_is_discarded(table) || |
| 7498 |
3/4✓ Branch 0 taken 30067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16000 times.
✓ Branch 3 taken 14067 times.
|
30067 | !dict_stats_is_persistent_enabled(table)) { |
| 7499 | 16004 | return; | |
| 7500 | } | ||
| 7501 | |||
| 7502 | #ifdef UNIV_DEBUG | ||
| 7503 | 14067 | bool ibd_file_missing_orig = false; | |
| 7504 | #endif /* UNIV_DEBUG */ | ||
| 7505 | |||
| 7506 |
3/4✓ Branch 0 taken 14067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14066 times.
|
14067 | DBUG_EXECUTE_IF("ib_rename_index_fail2", |
| 7507 | ibd_file_missing_orig = table->ibd_file_missing; | ||
| 7508 | table->ibd_file_missing = true;); | ||
| 7509 | |||
| 7510 |
1/2✓ Branch 0 taken 14067 times.
✗ Branch 1 not taken.
|
14067 | dberr_t ret = dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT); |
| 7511 | |||
| 7512 |
3/4✓ Branch 0 taken 14067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14066 times.
|
14067 | DBUG_EXECUTE_IF("ib_rename_index_fail2", |
| 7513 | table->ibd_file_missing = ibd_file_missing_orig;); | ||
| 7514 | |||
| 7515 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14066 times.
|
14067 | if (ret != DB_SUCCESS) { |
| 7516 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_ALTER_INFO, |
| 7517 | "Error updating stats for table '%s'" | ||
| 7518 | " after table rebuild: %s", | ||
| 7519 | table_name, ut_strerr(ret)); | ||
| 7520 | } | ||
| 7521 |
2/2✓ Branch 0 taken 14067 times.
✓ Branch 1 taken 16004 times.
|
30071 | } |
| 7522 | |||
| 7523 | /** Implementation of commit_inplace_alter_table() | ||
| 7524 | @tparam Table dd::Table or dd::Partition | ||
| 7525 | @param[in] altered_table TABLE object for new version of table. | ||
| 7526 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 7527 | by ALTER TABLE and holding data used | ||
| 7528 | during in-place alter. | ||
| 7529 | @param[in] commit True to commit or false to rollback. | ||
| 7530 | @param[in,out] new_dd_tab Table object for the new version of the | ||
| 7531 | table. Can be adjusted by this call. | ||
| 7532 | Changes to the table definition | ||
| 7533 | will be persisted in the data-dictionary | ||
| 7534 | at statement version of it. | ||
| 7535 | @retval true Failure | ||
| 7536 | @retval false Success */ | ||
| 7537 | template <typename Table> | ||
| 7538 | 53113 | bool ha_innobase::commit_inplace_alter_table_impl( | |
| 7539 | TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit, | ||
| 7540 | Table *new_dd_tab) { | ||
| 7541 | dberr_t error; | ||
| 7542 | ha_innobase_inplace_ctx *ctx0; | ||
| 7543 |
1/2✓ Branch 0 taken 53113 times.
✗ Branch 1 not taken.
|
53113 | struct mtr_buf_copy_t logs; |
| 7544 | |||
| 7545 | 53113 | ctx0 = static_cast<ha_innobase_inplace_ctx *>(ha_alter_info->handler_ctx); | |
| 7546 | |||
| 7547 | #ifdef UNIV_DEBUG | ||
| 7548 | 53113 | uint crash_inject_count = 1; | |
| 7549 | 53113 | uint crash_fail_inject_count = 1; | |
| 7550 | 53113 | uint failure_inject_count = 1; | |
| 7551 | #endif /* UNIV_DEBUG */ | ||
| 7552 | |||
| 7553 |
1/2✓ Branch 0 taken 53113 times.
✗ Branch 1 not taken.
|
53113 | DBUG_TRACE; |
| 7554 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53113 times.
|
53113 | assert(!srv_read_only_mode); |
| 7555 |
3/4✓ Branch 0 taken 45079 times.
✓ Branch 1 taken 8034 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45079 times.
|
53113 | assert(!ctx0 || ctx0->prebuilt == m_prebuilt); |
| 7556 |
3/4✓ Branch 0 taken 45079 times.
✓ Branch 1 taken 8034 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45079 times.
|
53113 | assert(!ctx0 || ctx0->old_table == m_prebuilt->table); |
| 7557 | |||
| 7558 |
3/4✓ Branch 0 taken 51451 times.
✓ Branch 1 taken 1662 times.
✓ Branch 2 taken 51451 times.
✗ Branch 3 not taken.
|
53113 | DEBUG_SYNC_C("innodb_commit_inplace_alter_table_enter"); |
| 7559 | |||
| 7560 |
3/4✓ Branch 0 taken 51451 times.
✓ Branch 1 taken 1662 times.
✓ Branch 2 taken 51451 times.
✗ Branch 3 not taken.
|
53113 | DEBUG_SYNC_C("innodb_commit_inplace_alter_table_wait"); |
| 7561 | |||
| 7562 |
4/4✓ Branch 0 taken 45079 times.
✓ Branch 1 taken 8034 times.
✓ Branch 2 taken 33208 times.
✓ Branch 3 taken 11871 times.
|
53113 | if (ctx0 != nullptr && ctx0->m_stage != nullptr) { |
| 7563 |
1/2✓ Branch 0 taken 33208 times.
✗ Branch 1 not taken.
|
33208 | ctx0->m_stage->begin_phase_end(); |
| 7564 | } | ||
| 7565 | |||
| 7566 |
2/2✓ Branch 0 taken 393 times.
✓ Branch 1 taken 52720 times.
|
53113 | if (!commit) { |
| 7567 | /* A rollback is being requested. So far we may at | ||
| 7568 | most have created some indexes. If any indexes were to | ||
| 7569 | be dropped, they would actually be dropped in this | ||
| 7570 | method if commit=true. */ | ||
| 7571 | const bool ret = | ||
| 7572 |
1/2✓ Branch 0 taken 393 times.
✗ Branch 1 not taken.
|
393 | rollback_inplace_alter_table(ha_alter_info, table, m_prebuilt); |
| 7573 | 393 | return ret; | |
| 7574 | } | ||
| 7575 | |||
| 7576 |
6/6✓ Branch 0 taken 46068 times.
✓ Branch 1 taken 6652 times.
✓ Branch 2 taken 1123 times.
✓ Branch 3 taken 44945 times.
✓ Branch 4 taken 7775 times.
✓ Branch 5 taken 44945 times.
|
98788 | if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) || |
| 7577 | 46068 | is_instant(ha_alter_info)) { | |
| 7578 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7775 times.
|
7775 | assert(!ctx0); |
| 7579 | 7775 | MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); | |
| 7580 | 7775 | ha_alter_info->group_commit_ctx = nullptr; | |
| 7581 | 7775 | return false; | |
| 7582 | } | ||
| 7583 | |||
| 7584 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44945 times.
|
44945 | assert(ctx0); |
| 7585 | |||
| 7586 | inplace_alter_handler_ctx **ctx_array; | ||
| 7587 | inplace_alter_handler_ctx *ctx_single[2]; | ||
| 7588 | |||
| 7589 |
2/2✓ Branch 0 taken 698 times.
✓ Branch 1 taken 44247 times.
|
44945 | if (ha_alter_info->group_commit_ctx) { |
| 7590 | 698 | ctx_array = ha_alter_info->group_commit_ctx; | |
| 7591 | } else { | ||
| 7592 | 44247 | ctx_single[0] = ctx0; | |
| 7593 | 44247 | ctx_single[1] = nullptr; | |
| 7594 | 44247 | ctx_array = ctx_single; | |
| 7595 | } | ||
| 7596 | |||
| 7597 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44945 times.
|
44945 | assert(ctx0 == ctx_array[0]); |
| 7598 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44945 times.
|
44945 | ut_ad(m_prebuilt->table == ctx0->old_table); |
| 7599 | 44945 | ha_alter_info->group_commit_ctx = nullptr; | |
| 7600 | |||
| 7601 |
1/2✓ Branch 0 taken 44945 times.
✗ Branch 1 not taken.
|
44945 | trx_start_if_not_started_xa(m_prebuilt->trx, true, UT_LOCATION_HERE); |
| 7602 | |||
| 7603 |
2/2✓ Branch 0 taken 47303 times.
✓ Branch 1 taken 44945 times.
|
92248 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7604 | 47303 | ha_innobase_inplace_ctx *ctx = | |
| 7605 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47303 times.
|
47303 | assert(ctx->prebuilt->trx == m_prebuilt->trx); |
| 7607 | |||
| 7608 | /* Exclusively lock the table, to ensure that no other | ||
| 7609 | transaction is holding locks on the table while we | ||
| 7610 | change the table definition. The MySQL meta-data lock | ||
| 7611 | should normally guarantee that no conflicting locks | ||
| 7612 | exist. However, FOREIGN KEY constraints checks and any | ||
| 7613 | transactions collected during crash recovery could be | ||
| 7614 | holding InnoDB locks only, not MySQL locks. */ | ||
| 7615 | |||
| 7616 | 47303 | error = ddl::lock_table(m_prebuilt->trx, ctx->old_table, LOCK_X); | |
| 7617 | |||
| 7618 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47303 times.
|
47303 | if (error != DB_SUCCESS) { |
| 7619 | ✗ | my_error_innodb(error, table_share->table_name.str, 0); | |
| 7620 | ✗ | return true; | |
| 7621 | } | ||
| 7622 | } | ||
| 7623 | |||
| 7624 |
3/4✓ Branch 0 taken 43586 times.
✓ Branch 1 taken 1359 times.
✓ Branch 2 taken 43586 times.
✗ Branch 3 not taken.
|
44945 | DEBUG_SYNC(m_user_thd, "innodb_alter_commit_after_lock_table"); |
| 7625 | |||
| 7626 | 44945 | const bool new_clustered = ctx0->need_rebuild(); | |
| 7627 | 44945 | trx_t *trx = ctx0->trx; | |
| 7628 | 44945 | bool fail = false; | |
| 7629 | |||
| 7630 |
2/2✓ Branch 0 taken 28228 times.
✓ Branch 1 taken 16717 times.
|
44945 | if (new_clustered) { |
| 7631 |
2/2✓ Branch 0 taken 30252 times.
✓ Branch 1 taken 28228 times.
|
58480 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7632 | 30252 | ha_innobase_inplace_ctx *ctx = | |
| 7633 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7634 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30252 times.
|
30252 | assert(ctx->need_rebuild()); |
| 7635 | |||
| 7636 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 30216 times.
|
30252 | if (ctx->old_table->fts) { |
| 7637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | ut_ad(!ctx->old_table->fts->add_wq); |
| 7638 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | fts_optimize_remove_table(ctx->old_table); |
| 7639 | } | ||
| 7640 | |||
| 7641 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 30136 times.
|
30252 | if (ctx->new_table->fts) { |
| 7642 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
|
116 | ut_ad(!ctx->new_table->fts->add_wq); |
| 7643 |
1/2✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
|
116 | fts_optimize_remove_table(ctx->new_table); |
| 7644 | } | ||
| 7645 | } | ||
| 7646 | } | ||
| 7647 | |||
| 7648 |
2/2✓ Branch 0 taken 11864 times.
✓ Branch 1 taken 33081 times.
|
44945 | if (trx == nullptr) { |
| 7649 | 11864 | trx = m_prebuilt->trx; | |
| 7650 | 11864 | ctx0->trx = trx; | |
| 7651 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11864 times.
|
11864 | assert(!new_clustered); |
| 7652 | } | ||
| 7653 | |||
| 7654 | /* Generate the temporary name for old table, and acquire mdl | ||
| 7655 | lock on it. */ | ||
| 7656 |
1/2✓ Branch 0 taken 44945 times.
✗ Branch 1 not taken.
|
44945 | THD *thd = current_thd; |
| 7657 |
2/2✓ Branch 0 taken 47303 times.
✓ Branch 1 taken 44945 times.
|
92248 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7658 | 47303 | ha_innobase_inplace_ctx *ctx = | |
| 7659 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7660 | |||
| 7661 |
2/2✓ Branch 0 taken 30252 times.
✓ Branch 1 taken 17051 times.
|
47303 | if (ctx->need_rebuild()) { |
| 7662 | 60504 | ctx->tmp_name = dict_mem_create_temporary_tablename( | |
| 7663 |
1/2✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
|
30252 | ctx->heap, ctx->new_table->name.m_name, ctx->new_table->id); |
| 7664 | |||
| 7665 | 30252 | std::string db_str; | |
| 7666 | 30252 | std::string tbl_str; | |
| 7667 |
2/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30252 times.
✗ Branch 3 not taken.
|
30252 | dict_name::get_table(ctx->tmp_name, db_str, tbl_str); |
| 7668 | |||
| 7669 | /* Acquire mdl lock on the temporary table name. */ | ||
| 7670 | 30252 | MDL_ticket *mdl_ticket = nullptr; | |
| 7671 |
2/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30252 times.
|
30252 | if (dd::acquire_exclusive_table_mdl(thd, db_str.c_str(), tbl_str.c_str(), |
| 7672 | false, &mdl_ticket)) { | ||
| 7673 | ✗ | return true; | |
| 7674 | } | ||
| 7675 |
2/4✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30252 times.
✗ Branch 3 not taken.
|
30252 | } |
| 7676 | } | ||
| 7677 | |||
| 7678 | /* Latch the InnoDB data dictionary exclusively so that no deadlocks | ||
| 7679 | or lock waits can happen in it during the data dictionary operation. */ | ||
| 7680 |
1/2✓ Branch 0 taken 44945 times.
✗ Branch 1 not taken.
|
44945 | row_mysql_lock_data_dictionary(trx, UT_LOCATION_HERE); |
| 7681 | |||
| 7682 | /* Prevent the background statistics collection from accessing | ||
| 7683 | the tables. */ | ||
| 7684 | ✗ | for (;;) { | |
| 7685 | 44945 | bool retry = false; | |
| 7686 | |||
| 7687 |
2/2✓ Branch 0 taken 47303 times.
✓ Branch 1 taken 44945 times.
|
92248 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7688 | 47303 | ha_innobase_inplace_ctx *ctx = | |
| 7689 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7690 | |||
| 7691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47303 times.
|
47303 | assert(new_clustered == ctx->need_rebuild()); |
| 7692 | |||
| 7693 |
5/8✓ Branch 0 taken 30252 times.
✓ Branch 1 taken 17051 times.
✓ Branch 2 taken 30252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30252 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 47303 times.
|
47303 | if (new_clustered && !dict_stats_stop_bg(ctx->old_table)) { |
| 7694 | ✗ | retry = true; | |
| 7695 | } | ||
| 7696 | |||
| 7697 |
2/4✓ Branch 0 taken 47303 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47303 times.
|
47303 | if (!dict_stats_stop_bg(ctx->new_table)) { |
| 7698 | ✗ | retry = true; | |
| 7699 | } | ||
| 7700 | } | ||
| 7701 | |||
| 7702 |
1/2✓ Branch 0 taken 44945 times.
✗ Branch 1 not taken.
|
44945 | if (!retry) { |
| 7703 | 44945 | break; | |
| 7704 | } | ||
| 7705 | |||
| 7706 | ✗ | DICT_STATS_BG_YIELD(trx, UT_LOCATION_HERE); | |
| 7707 | } | ||
| 7708 | |||
| 7709 | /* Apply the changes to the data dictionary tables, for all partitions.*/ | ||
| 7710 | |||
| 7711 |
3/4✓ Branch 0 taken 44944 times.
✓ Branch 1 taken 47303 times.
✓ Branch 2 taken 47303 times.
✗ Branch 3 not taken.
|
92247 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx && !fail; pctx++) { |
| 7712 | 47303 | ha_innobase_inplace_ctx *ctx = | |
| 7713 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7714 | |||
| 7715 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47303 times.
|
47303 | assert(new_clustered == ctx->need_rebuild()); |
| 7716 | |||
| 7717 |
1/2✓ Branch 0 taken 47303 times.
✗ Branch 1 not taken.
|
47303 | fail = commit_get_autoinc(ha_alter_info, ctx, altered_table, table); |
| 7718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47303 times.
|
47303 | if (fail) { |
| 7719 | ✗ | my_error(ER_TABLESPACE_DISCARDED, MYF(0), table->s->table_name.str); | |
| 7720 | ✗ | goto rollback_trx; | |
| 7721 | } | ||
| 7722 | |||
| 7723 |
2/2✓ Branch 0 taken 30252 times.
✓ Branch 1 taken 17051 times.
|
47303 | if (ctx->need_rebuild()) { |
| 7724 | 60504 | fail = commit_try_rebuild(ha_alter_info, ctx, altered_table, table, trx, | |
| 7725 |
1/2✓ Branch 0 taken 30252 times.
✗ Branch 1 not taken.
|
30252 | table_share->table_name.str); |
| 7726 | |||
| 7727 |
2/2✓ Branch 0 taken 30251 times.
✓ Branch 1 taken 1 times.
|
30252 | if (!fail) { |
| 7728 |
1/2✓ Branch 0 taken 30250 times.
✗ Branch 1 not taken.
|
30251 | log_ddl->write_drop_log(trx, ctx->old_table->id); |
| 7729 | } | ||
| 7730 | } else { | ||
| 7731 | 17051 | fail = commit_try_norebuild(ha_alter_info, ctx, trx, | |
| 7732 |
1/2✓ Branch 0 taken 17051 times.
✗ Branch 1 not taken.
|
17051 | table_share->table_name.str); |
| 7733 | } | ||
| 7734 |
2/6✓ Branch 0 taken 47302 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47302 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
47302 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 7735 | #ifdef UNIV_DEBUG | ||
| 7736 | { | ||
| 7737 | /* Generate a dynamic dbug text. */ | ||
| 7738 | char buf[32]; | ||
| 7739 | |||
| 7740 | 47302 | snprintf(buf, sizeof buf, "ib_commit_inplace_fail_%u", | |
| 7741 | failure_inject_count++); | ||
| 7742 | |||
| 7743 |
2/6✓ Branch 0 taken 47302 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47302 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
47302 | DBUG_EXECUTE_IF(buf, |
| 7744 | my_error(ER_INTERNAL_ERROR, MYF(0), "Injected error!"); | ||
| 7745 | fail = true;); | ||
| 7746 | } | ||
| 7747 | #endif | ||
| 7748 | } | ||
| 7749 | |||
| 7750 | 44944 | rollback_trx: | |
| 7751 | |||
| 7752 | /* Commit or roll back the changes to the data dictionary. */ | ||
| 7753 | |||
| 7754 |
4/4✓ Branch 0 taken 44936 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 28226 times.
✓ Branch 3 taken 16710 times.
|
44944 | if (!fail && new_clustered) { |
| 7755 |
2/2✓ Branch 0 taken 30250 times.
✓ Branch 1 taken 28226 times.
|
58476 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7756 | 30250 | ha_innobase_inplace_ctx *ctx = | |
| 7757 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7758 | |||
| 7759 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30250 times.
|
30250 | assert(ctx->need_rebuild()); |
| 7760 | |||
| 7761 | /* Check for any possible problems for any | ||
| 7762 | file operations that will be performed in | ||
| 7763 | commit_cache_rebuild(). */ | ||
| 7764 | error = | ||
| 7765 |
1/2✓ Branch 0 taken 30250 times.
✗ Branch 1 not taken.
|
30250 | fil_rename_precheck(ctx->old_table, ctx->new_table, ctx->tmp_name); |
| 7766 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30247 times.
|
30250 | if (error != DB_SUCCESS) { |
| 7767 | /* Out of memory or a problem will occur | ||
| 7768 | when renaming files. */ | ||
| 7769 | 3 | fail = true; | |
| 7770 | 3 | my_error_innodb(error, ctx->old_table->name.m_name, | |
| 7771 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | ctx->old_table->flags); |
| 7772 | } | ||
| 7773 |
2/6✓ Branch 0 taken 30250 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30250 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30250 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 7774 | } | ||
| 7775 | |||
| 7776 | /* Test what happens on crash here. | ||
| 7777 | The data dictionary transaction should be | ||
| 7778 | rolled back, restoring the old table. */ | ||
| 7779 |
5/8✓ Branch 0 taken 28226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 28225 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
28226 | DBUG_EXECUTE_IF("innodb_alter_commit_crash_before_commit", |
| 7780 | log_buffer_flush_to_disk(); | ||
| 7781 | DBUG_SUICIDE();); | ||
| 7782 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28225 times.
|
28225 | ut_ad(!trx->fts_trx); |
| 7783 | |||
| 7784 |
6/10✓ Branch 0 taken 28225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 28223 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
|
28225 | DBUG_EXECUTE_IF("innodb_alter_commit_crash_after_commit", |
| 7785 | log_make_latest_checkpoint(); | ||
| 7786 | log_buffer_flush_to_disk(); DBUG_SUICIDE();); | ||
| 7787 | } | ||
| 7788 | |||
| 7789 | /* Update the in-memory structures, close some handles, release | ||
| 7790 | temporary files, and (unless we rolled back) update persistent | ||
| 7791 | statistics. */ | ||
| 7792 |
2/2✓ Branch 0 taken 47251 times.
✓ Branch 1 taken 44877 times.
|
92128 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7793 | 47251 | ha_innobase_inplace_ctx *ctx = | |
| 7794 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7795 | |||
| 7796 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47251 times.
|
47251 | assert(ctx->need_rebuild() == new_clustered); |
| 7797 | |||
| 7798 |
2/2✓ Branch 0 taken 30212 times.
✓ Branch 1 taken 17039 times.
|
47251 | if (new_clustered) { |
| 7799 |
1/2✓ Branch 0 taken 30212 times.
✗ Branch 1 not taken.
|
30212 | innobase_online_rebuild_log_free(ctx->old_table); |
| 7800 | } | ||
| 7801 | |||
| 7802 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 47240 times.
|
47251 | if (fail) { |
| 7803 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | if (new_clustered) { |
| 7804 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | dict_table_close(ctx->new_table, true, false); |
| 7805 | 4 | ctx->new_table = nullptr; | |
| 7806 | } else { | ||
| 7807 | /* We failed, but did not rebuild the table. | ||
| 7808 | Roll back any ADD INDEX, or get rid of garbage | ||
| 7809 | ADD INDEX that was left over from a previous | ||
| 7810 | ALTER TABLE statement. */ | ||
| 7811 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | innobase_rollback_sec_index(ctx->new_table, table, true, trx); |
| 7812 | } | ||
| 7813 |
2/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
11 | DBUG_INJECT_CRASH("ib_commit_inplace_crash_fail", |
| 7814 | crash_fail_inject_count++); | ||
| 7815 | |||
| 7816 | 11 | continue; | |
| 7817 | 11 | } | |
| 7818 | |||
| 7819 |
1/2✓ Branch 0 taken 47240 times.
✗ Branch 1 not taken.
|
47240 | innobase_copy_frm_flags_from_table_share(ctx->new_table, altered_table->s); |
| 7820 | |||
| 7821 |
2/2✓ Branch 0 taken 30208 times.
✓ Branch 1 taken 17032 times.
|
47240 | if (new_clustered) { |
| 7822 | /* We will reload and refresh the | ||
| 7823 | in-memory foreign key constraint | ||
| 7824 | metadata. This is a rename operation | ||
| 7825 | in preparing for dropping the old | ||
| 7826 | table. Set the table to_be_dropped bit | ||
| 7827 | here, so to make sure DML foreign key | ||
| 7828 | constraint check does not use the | ||
| 7829 | stale dict_foreign_t. This is done | ||
| 7830 | because WL#6049 (FK MDL) has not been | ||
| 7831 | implemented yet. */ | ||
| 7832 | 30208 | ctx->old_table->to_be_dropped = true; | |
| 7833 | |||
| 7834 |
3/8✓ Branch 0 taken 30208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30208 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
30208 | DBUG_PRINT("to_be_dropped", ("table: %s", ctx->old_table->name.m_name)); |
| 7835 | |||
| 7836 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 30194 times.
|
30208 | if ((ha_alter_info->handler_flags & |
| 7837 | Alter_inplace_info::ALTER_COLUMN_NAME)) { | ||
| 7838 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | innobase_rename_col_discard_foreign(ha_alter_info, table, |
| 7839 | ctx->old_table); | ||
| 7840 | } | ||
| 7841 | |||
| 7842 | /* Rename the tablespace files. */ | ||
| 7843 |
1/2✓ Branch 0 taken 30160 times.
✗ Branch 1 not taken.
|
30208 | commit_cache_rebuild(ctx); |
| 7844 | |||
| 7845 | /* Discard the added foreign keys, because we will | ||
| 7846 | load them from the data dictionary. */ | ||
| 7847 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 30160 times.
|
30167 | for (ulint i = 0; i < ctx->num_to_add_fk; i++) { |
| 7848 | 7 | dict_foreign_t *fk = ctx->add_fk[i]; | |
| 7849 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | dict_foreign_free(fk); |
| 7850 | } | ||
| 7851 | |||
| 7852 | /* There is no FK on partition table */ | ||
| 7853 |
2/2✓ Branch 0 taken 27653 times.
✓ Branch 1 taken 2507 times.
|
30160 | if (m_share) { |
| 7854 | 27653 | ctx->new_table->discard_after_ddl = true; | |
| 7855 | } | ||
| 7856 | } else { | ||
| 7857 | error = | ||
| 7858 |
1/2✓ Branch 0 taken 17032 times.
✗ Branch 1 not taken.
|
17032 | innobase_update_foreign_cache(ctx, m_user_thd, &new_dd_tab->table()); |
| 7859 | |||
| 7860 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17032 times.
|
17032 | if (error != DB_SUCCESS) { |
| 7861 | /* The data dictionary cache | ||
| 7862 | should be corrupted now. The | ||
| 7863 | best solution should be to | ||
| 7864 | kill and restart the server, | ||
| 7865 | but the *.frm file has not | ||
| 7866 | been replaced yet. */ | ||
| 7867 | ✗ | push_warning_printf(m_user_thd, Sql_condition::SL_WARNING, | |
| 7868 | ER_ALTER_INFO, | ||
| 7869 | "InnoDB: Could not add foreign" | ||
| 7870 | " key constraints."); | ||
| 7871 | } else { | ||
| 7872 |
2/4✓ Branch 0 taken 17016 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17016 times.
|
17032 | if (!commit_cache_norebuild(ctx, trx)) { |
| 7873 | ✗ | ut_a(!m_prebuilt->trx->check_foreigns); | |
| 7874 | } | ||
| 7875 | |||
| 7876 |
1/2✓ Branch 0 taken 17016 times.
✗ Branch 1 not taken.
|
17016 | innobase_rename_or_enlarge_columns_cache(ha_alter_info, table, |
| 7877 | ctx->new_table); | ||
| 7878 | |||
| 7879 |
1/2✓ Branch 0 taken 17016 times.
✗ Branch 1 not taken.
|
17016 | rename_indexes_in_cache(ctx, ha_alter_info); |
| 7880 | } | ||
| 7881 | } | ||
| 7882 | |||
| 7883 |
1/2✓ Branch 0 taken 47176 times.
✗ Branch 1 not taken.
|
47176 | dict_mem_table_free_foreign_vcol_set(ctx->new_table); |
| 7884 |
1/2✓ Branch 0 taken 47176 times.
✗ Branch 1 not taken.
|
47176 | dict_mem_table_fill_foreign_vcol_set(ctx->new_table); |
| 7885 | |||
| 7886 |
2/6✓ Branch 0 taken 47176 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47176 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
47176 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 7887 | } | ||
| 7888 | |||
| 7889 | /* Invalidate the index translation table. In partitioned | ||
| 7890 | tables, there is no share. */ | ||
| 7891 |
2/2✓ Branch 0 taken 44227 times.
✓ Branch 1 taken 650 times.
|
44877 | if (m_share) { |
| 7892 | 44227 | m_share->idx_trans_tbl.index_count = 0; | |
| 7893 | } | ||
| 7894 | |||
| 7895 | /* Tell the InnoDB server that there might be work for | ||
| 7896 | utility threads: */ | ||
| 7897 | |||
| 7898 |
1/2✓ Branch 0 taken 44877 times.
✗ Branch 1 not taken.
|
44877 | srv_active_wake_master_thread(); |
| 7899 | |||
| 7900 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 44866 times.
|
44877 | if (fail) { |
| 7901 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
|
22 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7902 | 11 | ha_innobase_inplace_ctx *ctx = | |
| 7903 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7904 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | assert(ctx->need_rebuild() == new_clustered); |
| 7905 | |||
| 7906 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | ut_d(dict_table_check_for_dup_indexes(ctx->old_table, CHECK_ABORTED_OK)); |
| 7907 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | ut_a(fts_check_cached_index(ctx->old_table)); |
| 7908 |
2/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
11 | DBUG_INJECT_CRASH("ib_commit_inplace_crash_fail", |
| 7909 | crash_fail_inject_count++); | ||
| 7910 | } | ||
| 7911 | |||
| 7912 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | row_mysql_unlock_data_dictionary(trx); |
| 7913 | 11 | return true; | |
| 7914 | } | ||
| 7915 | |||
| 7916 |
2/2✓ Branch 0 taken 44773 times.
✓ Branch 1 taken 93 times.
|
44866 | if (ha_alter_info->virtual_column_drop_count || |
| 7917 |
2/2✓ Branch 0 taken 284 times.
✓ Branch 1 taken 44489 times.
|
44773 | ha_alter_info->virtual_column_add_count) { |
| 7918 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 377 times.
|
377 | if (ctx0->old_table->get_ref_count() > 1) { |
| 7919 | ✗ | row_mysql_unlock_data_dictionary(trx); | |
| 7920 | ✗ | my_error(ER_TABLE_REFERENCED, MYF(0)); | |
| 7921 | ✗ | return true; | |
| 7922 | } | ||
| 7923 | |||
| 7924 |
2/2✓ Branch 0 taken 377 times.
✓ Branch 1 taken 377 times.
|
754 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7925 | 377 | ha_innobase_inplace_ctx *ctx = | |
| 7926 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7927 | |||
| 7928 | /* Drop outdated table stats. */ | ||
| 7929 |
1/2✓ Branch 0 taken 377 times.
✗ Branch 1 not taken.
|
377 | innobase_discard_table(m_user_thd, ctx->old_table); |
| 7930 | } | ||
| 7931 | |||
| 7932 |
1/2✓ Branch 0 taken 377 times.
✗ Branch 1 not taken.
|
377 | row_mysql_unlock_data_dictionary(trx); |
| 7933 | 377 | MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); | |
| 7934 | 377 | return false; | |
| 7935 | } | ||
| 7936 | |||
| 7937 |
2/6✓ Branch 0 taken 44489 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 44489 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
44489 | DBUG_EXECUTE_IF("ib_ddl_crash_after_user_trx_commit", DBUG_SUICIDE();); |
| 7938 | |||
| 7939 | 44489 | uint64_t autoinc = 0; | |
| 7940 |
2/2✓ Branch 0 taken 46739 times.
✓ Branch 1 taken 44460 times.
|
91199 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 7941 | 46739 | ha_innobase_inplace_ctx *ctx = | |
| 7942 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 7943 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46739 times.
|
46739 | assert(ctx->need_rebuild() == new_clustered); |
| 7944 | |||
| 7945 |
2/2✓ Branch 0 taken 4230 times.
✓ Branch 1 taken 42509 times.
|
46739 | if (altered_table->found_next_number_field) { |
| 7946 |
2/2✓ Branch 0 taken 4028 times.
✓ Branch 1 taken 202 times.
|
4230 | if (ctx->max_autoinc > autoinc) { |
| 7947 | 4028 | autoinc = ctx->max_autoinc; | |
| 7948 | } | ||
| 7949 | |||
| 7950 | 4230 | dict_table_t *t = ctx->new_table; | |
| 7951 | 4230 | Field *field = altered_table->found_next_number_field; | |
| 7952 | |||
| 7953 |
1/2✓ Branch 0 taken 4230 times.
✗ Branch 1 not taken.
|
4230 | dict_table_autoinc_lock(t); |
| 7954 |
1/2✓ Branch 0 taken 4230 times.
✗ Branch 1 not taken.
|
4230 | dict_table_autoinc_initialize(t, ctx->max_autoinc); |
| 7955 | 4230 | t->autoinc_persisted = ctx->max_autoinc - 1; | |
| 7956 |
1/2✓ Branch 0 taken 4230 times.
✗ Branch 1 not taken.
|
4230 | dict_table_autoinc_set_col_pos(t, field->field_index()); |
| 7957 |
1/2✓ Branch 0 taken 4230 times.
✗ Branch 1 not taken.
|
4230 | dict_table_autoinc_unlock(t); |
| 7958 | } | ||
| 7959 | |||
| 7960 | 46739 | bool add_fts = false; | |
| 7961 | |||
| 7962 | /* Publish the created fulltext index, if any. | ||
| 7963 | Note that a fulltext index can be created without | ||
| 7964 | creating the clustered index, if there already exists | ||
| 7965 | a suitable FTS_DOC_ID column. If not, one will be | ||
| 7966 | created, implying new_clustered */ | ||
| 7967 |
2/2✓ Branch 0 taken 44514 times.
✓ Branch 1 taken 46739 times.
|
91253 | for (ulint i = 0; i < ctx->num_to_add_index; i++) { |
| 7968 | 44514 | dict_index_t *index = ctx->add_index[i]; | |
| 7969 | |||
| 7970 |
2/2✓ Branch 0 taken 446 times.
✓ Branch 1 taken 44068 times.
|
44514 | if (index->type & DICT_FTS) { |
| 7971 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 446 times.
|
446 | assert(index->type == DICT_FTS); |
| 7972 | /* We reset DICT_TF2_FTS here because the bit | ||
| 7973 | is left unset when a drop proceeds the add. */ | ||
| 7974 | 446 | DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); | |
| 7975 |
1/2✓ Branch 0 taken 446 times.
✗ Branch 1 not taken.
|
446 | fts_add_index(index, ctx->new_table); |
| 7976 | 446 | add_fts = true; | |
| 7977 | } | ||
| 7978 | } | ||
| 7979 | |||
| 7980 |
1/2✓ Branch 0 taken 46739 times.
✗ Branch 1 not taken.
|
46739 | ut_d(dict_table_check_for_dup_indexes(ctx->new_table, CHECK_ALL_COMPLETE)); |
| 7981 | |||
| 7982 |
4/4✓ Branch 0 taken 446 times.
✓ Branch 1 taken 46293 times.
✓ Branch 2 taken 330 times.
✓ Branch 3 taken 116 times.
|
46739 | if (add_fts && !ctx->new_table->discard_after_ddl) { |
| 7983 |
1/2✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
|
330 | fts_optimize_add_table(ctx->new_table); |
| 7984 | } | ||
| 7985 | |||
| 7986 |
1/2✓ Branch 0 taken 46739 times.
✗ Branch 1 not taken.
|
46739 | ut_d(dict_table_check_for_dup_indexes(ctx->new_table, CHECK_ABORTED_OK)); |
| 7987 |
2/4✓ Branch 0 taken 46739 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46739 times.
|
46739 | ut_a(fts_check_cached_index(ctx->new_table)); |
| 7988 | |||
| 7989 |
2/2✓ Branch 0 taken 30112 times.
✓ Branch 1 taken 16627 times.
|
46739 | if (new_clustered) { |
| 7990 | /* Since the table has been rebuilt, we remove | ||
| 7991 | all persistent statistics corresponding to the | ||
| 7992 | old copy of the table (which was renamed to | ||
| 7993 | ctx->tmp_name). */ | ||
| 7994 | |||
| 7995 | char errstr[ERROR_STR_LENGTH]; | ||
| 7996 | |||
| 7997 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30112 times.
|
30112 | assert(0 == strcmp(ctx->old_table->name.m_name, ctx->tmp_name)); |
| 7998 | |||
| 7999 |
4/6✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30111 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
30112 | DBUG_EXECUTE_IF("ib_rename_index_fail3", |
| 8000 | DBUG_SET("+d,innodb_report_deadlock");); | ||
| 8001 | |||
| 8002 |
1/2✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
|
30112 | if (dict_stats_drop_table(ctx->new_table->name.m_name, errstr, |
| 8003 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30111 times.
|
30112 | sizeof(errstr)) != DB_SUCCESS) { |
| 8004 | 1 | push_warning_printf(m_user_thd, Sql_condition::SL_WARNING, | |
| 8005 | ER_ALTER_INFO, | ||
| 8006 | "Deleting persistent statistics" | ||
| 8007 | " for rebuilt table '%s' in" | ||
| 8008 | " InnoDB failed: %s", | ||
| 8009 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | table->s->table_name.str, errstr); |
| 8010 | } | ||
| 8011 | |||
| 8012 |
4/6✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30111 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
30112 | DBUG_EXECUTE_IF("ib_rename_index_fail3", |
| 8013 | DBUG_SET("-d,innodb_report_deadlock");); | ||
| 8014 | |||
| 8015 |
2/6✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30112 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30112 | DBUG_EXECUTE_IF("ib_ddl_crash_before_commit", DBUG_SUICIDE();); |
| 8016 | |||
| 8017 |
4/6✓ Branch 0 taken 28172 times.
✓ Branch 1 taken 1940 times.
✓ Branch 2 taken 28172 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30112 times.
|
30112 | ut_ad(m_prebuilt != ctx->prebuilt || ctx == ctx0); |
| 8018 | 30112 | bool update_own_prebuilt = (m_prebuilt == ctx->prebuilt); | |
| 8019 | 30112 | trx_t *const user_trx = m_prebuilt->trx; | |
| 8020 |
3/4✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2459 times.
✓ Branch 3 taken 27653 times.
|
30112 | if (dict_table_is_partition(ctx->new_table)) { |
| 8021 | /* Set blob_heap to NULL for partitioned tables to avoid | ||
| 8022 | row_prebuilt_free() from freeing them. We do this to avoid double free | ||
| 8023 | of blob_heap since all partitions point to the same blob_heap in | ||
| 8024 | prebuilt. Blob heaps of all the partitions will be freed later in the | ||
| 8025 | ha_innopart::clear_blob_heaps() */ | ||
| 8026 | 2459 | ctx->prebuilt->blob_heap = nullptr; | |
| 8027 | } | ||
| 8028 | |||
| 8029 |
1/2✓ Branch 0 taken 30112 times.
✗ Branch 1 not taken.
|
30112 | row_prebuilt_free(ctx->prebuilt, true); |
| 8030 | |||
| 8031 | /* Drop the copy of the old table, which was | ||
| 8032 | renamed to ctx->tmp_name at the atomic DDL | ||
| 8033 | transaction commit. If the system crashes | ||
| 8034 | before this is completed, some orphan tables | ||
| 8035 | with ctx->tmp_name may be recovered. */ | ||
| 8036 | 30112 | ddl::drop_table(trx, ctx->old_table); | |
| 8037 | |||
| 8038 | /* Rebuild the prebuilt object. */ | ||
| 8039 | 30083 | ctx->prebuilt = | |
| 8040 |
1/2✓ Branch 0 taken 30083 times.
✗ Branch 1 not taken.
|
30083 | row_create_prebuilt(ctx->new_table, altered_table->s->reclength); |
| 8041 |
2/2✓ Branch 0 taken 28151 times.
✓ Branch 1 taken 1932 times.
|
30083 | if (update_own_prebuilt) { |
| 8042 | 28151 | m_prebuilt = ctx->prebuilt; | |
| 8043 | } | ||
| 8044 | 30083 | user_trx->will_lock++; | |
| 8045 | 30083 | m_prebuilt->trx = user_trx; | |
| 8046 | } | ||
| 8047 |
2/6✓ Branch 0 taken 46710 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46710 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
46710 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 8048 | } | ||
| 8049 | |||
| 8050 |
1/2✓ Branch 0 taken 44460 times.
✗ Branch 1 not taken.
|
44460 | row_mysql_unlock_data_dictionary(trx); |
| 8051 | |||
| 8052 |
2/2✓ Branch 0 taken 3963 times.
✓ Branch 1 taken 40497 times.
|
44460 | if (altered_table->found_next_number_field != nullptr) { |
| 8053 |
2/4✓ Branch 0 taken 3963 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3963 times.
✗ Branch 3 not taken.
|
3963 | dd_set_autoinc(new_dd_tab->se_private_data(), autoinc); |
| 8054 | } | ||
| 8055 | |||
| 8056 |
4/6✓ Branch 0 taken 44460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 44458 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
44460 | DBUG_EXECUTE_IF("ib_ddl_crash_before_update_stats", DBUG_SUICIDE();); |
| 8057 | |||
| 8058 | /* Rebuild index translation table now for temporary tables if we are | ||
| 8059 | restoring secondary keys, as ha_innobase::open will not be called for | ||
| 8060 | the next access. */ | ||
| 8061 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 44449 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 44454 times.
|
44467 | if (DICT_TF2_FLAG_IS_SET(ctx0->new_table, DICT_TF2_TEMPORARY) && |
| 8062 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
|
9 | ctx0->num_to_add_index) { |
| 8063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_ad(!ctx0->num_to_drop_index); |
| 8064 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_ad(!ctx0->num_to_rename); |
| 8065 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | ut_ad(!ctx0->num_to_drop_fk); |
| 8066 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (!innobase_build_index_translation(altered_table, ctx0->new_table, |
| 8067 | m_share)) { | ||
| 8068 | ✗ | MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); | |
| 8069 | ✗ | return true; | |
| 8070 | } | ||
| 8071 | } | ||
| 8072 | |||
| 8073 | /* TODO: The following code could be executed | ||
| 8074 | while allowing concurrent access to the table | ||
| 8075 | (MDL downgrade). */ | ||
| 8076 | |||
| 8077 |
2/2✓ Branch 0 taken 28143 times.
✓ Branch 1 taken 16315 times.
|
44458 | if (new_clustered) { |
| 8078 |
2/2✓ Branch 0 taken 30071 times.
✓ Branch 1 taken 28143 times.
|
58214 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 8079 | 30071 | ha_innobase_inplace_ctx *ctx = | |
| 8080 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 8081 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30071 times.
|
30071 | assert(ctx->need_rebuild()); |
| 8082 | |||
| 8083 |
1/2✓ Branch 0 taken 30071 times.
✗ Branch 1 not taken.
|
30071 | alter_stats_rebuild(ctx->new_table, table->s->table_name.str, m_user_thd); |
| 8084 |
2/6✓ Branch 0 taken 30071 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30071 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30071 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 8085 | } | ||
| 8086 | } else { | ||
| 8087 |
2/2✓ Branch 0 taken 16623 times.
✓ Branch 1 taken 16315 times.
|
32938 | for (inplace_alter_handler_ctx **pctx = ctx_array; *pctx; pctx++) { |
| 8088 | 16623 | ha_innobase_inplace_ctx *ctx = | |
| 8089 | static_cast<ha_innobase_inplace_ctx *>(*pctx); | ||
| 8090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16623 times.
|
16623 | assert(!ctx->need_rebuild()); |
| 8091 | |||
| 8092 |
1/2✓ Branch 0 taken 16623 times.
✗ Branch 1 not taken.
|
16623 | alter_stats_norebuild(ha_alter_info, ctx, table->s->table_name.str, |
| 8093 | m_user_thd); | ||
| 8094 |
2/6✓ Branch 0 taken 16623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16623 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
16623 | DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); |
| 8095 | |||
| 8096 |
5/6✓ Branch 0 taken 114 times.
✓ Branch 1 taken 16509 times.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 16509 times.
|
16737 | if (ctx->fts_drop_aux_vec != nullptr && |
| 8097 | 114 | ctx->fts_drop_aux_vec->aux_name.size() > 0) { | |
| 8098 | 114 | fts_drop_dd_tables(ctx->fts_drop_aux_vec, | |
| 8099 |
2/4✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
|
114 | dict_table_is_file_per_table(ctx->old_table)); |
| 8100 | } | ||
| 8101 | } | ||
| 8102 | } | ||
| 8103 | |||
| 8104 | /* We don't support compression for the system tablespace nor | ||
| 8105 | the temporary tablespace. Only because they are shared tablespaces. | ||
| 8106 | There is no other technical reason. */ | ||
| 8107 | |||
| 8108 | 44458 | innobase_parse_hint_from_comment(m_user_thd, m_prebuilt->table, | |
| 8109 |
1/2✓ Branch 0 taken 44458 times.
✗ Branch 1 not taken.
|
44458 | altered_table->s); |
| 8110 | |||
| 8111 | /* TODO: Also perform DROP TABLE and DROP INDEX after | ||
| 8112 | the MDL downgrade. */ | ||
| 8113 | |||
| 8114 | #ifdef UNIV_DEBUG | ||
| 8115 |
1/2✓ Branch 0 taken 44458 times.
✗ Branch 1 not taken.
|
44458 | dict_index_t *clust_index = ctx0->prebuilt->table->first_index(); |
| 8116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44458 times.
|
44458 | assert(!clust_index->online_log); |
| 8117 |
2/4✓ Branch 0 taken 44458 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 44458 times.
|
44458 | assert(dict_index_get_online_status(clust_index) == ONLINE_INDEX_COMPLETE); |
| 8118 | |||
| 8119 |
3/4✓ Branch 0 taken 63088 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63088 times.
✓ Branch 3 taken 44458 times.
|
107546 | for (dict_index_t *index = clust_index; index; index = index->next()) { |
| 8120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 63088 times.
|
63088 | assert(!index->to_be_dropped); |
| 8121 | } | ||
| 8122 | #endif /* UNIV_DEBUG */ | ||
| 8123 | 44458 | MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); | |
| 8124 | 44458 | return false; | |
| 8125 | 53014 | } | |
| 8126 | |||
| 8127 | /** Helper class for in-place alter partitioned table, see handler.h */ | ||
| 8128 | class ha_innopart_inplace_ctx : public inplace_alter_handler_ctx { | ||
| 8129 | /* Only used locally in this file, so have everything public for | ||
| 8130 | convenience. */ | ||
| 8131 | public: | ||
| 8132 | /** Total number of partitions. */ | ||
| 8133 | uint m_tot_parts; | ||
| 8134 | /** Array of inplace contexts for all partitions. */ | ||
| 8135 | inplace_alter_handler_ctx **ctx_array; | ||
| 8136 | /** Array of prebuilt for all partitions. */ | ||
| 8137 | row_prebuilt_t **prebuilt_array; | ||
| 8138 | /** Array of old table information needed for writing back to DD */ | ||
| 8139 | alter_table_old_info_t *m_old_info; | ||
| 8140 | |||
| 8141 | 1040 | ha_innopart_inplace_ctx(uint tot_parts) | |
| 8142 | 1040 | : inplace_alter_handler_ctx(), | |
| 8143 | 1040 | m_tot_parts(tot_parts), | |
| 8144 | 1040 | ctx_array(), | |
| 8145 | 1040 | prebuilt_array(), | |
| 8146 | 1040 | m_old_info() {} | |
| 8147 | |||
| 8148 | 1718 | ~ha_innopart_inplace_ctx() override { | |
| 8149 |
1/2✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
|
1718 | if (ctx_array) { |
| 8150 |
2/2✓ Branch 0 taken 3862 times.
✓ Branch 1 taken 859 times.
|
9442 | for (uint i = 0; i < m_tot_parts; i++) { |
| 8151 | 7724 | destroy(ctx_array[i]); | |
| 8152 | } | ||
| 8153 | 1718 | ut::free(ctx_array); | |
| 8154 | } | ||
| 8155 | |||
| 8156 |
1/2✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
|
1718 | if (m_old_info != nullptr) { |
| 8157 | 1718 | ut::free(m_old_info); | |
| 8158 | } | ||
| 8159 | |||
| 8160 |
1/2✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
|
1718 | if (prebuilt_array) { |
| 8161 | /* First entry is the original prebuilt! */ | ||
| 8162 |
2/2✓ Branch 0 taken 3003 times.
✓ Branch 1 taken 859 times.
|
7724 | for (uint i = 1; i < m_tot_parts; i++) { |
| 8163 | /* Don't close the tables. */ | ||
| 8164 | 6006 | prebuilt_array[i]->table = nullptr; | |
| 8165 | 6006 | row_prebuilt_free(prebuilt_array[i], false); | |
| 8166 | } | ||
| 8167 | 1718 | ut::free(prebuilt_array); | |
| 8168 | } | ||
| 8169 | } | ||
| 8170 | }; | ||
| 8171 | |||
| 8172 | /** Helper class for encapsulating new/altered partitions during | ||
| 8173 | ADD(HASH/KEY)/COALESCE/REORGANIZE PARTITION. Here as many partition slots | ||
| 8174 | as in new table would be created, it's OK for ADD/COALESCE PARTITION, | ||
| 8175 | however more partition slots would probably be created for REORGANIZE PARTITION. | ||
| 8176 | Considering that it's easy to get table in this way, it's still OK. */ | ||
| 8177 | class Altered_partitions { | ||
| 8178 | public: | ||
| 8179 | /** Constructor | ||
| 8180 | @param[in] parts total partitions */ | ||
| 8181 | 593 | Altered_partitions(uint parts) | |
| 8182 | 593 | : m_new_table_parts(), | |
| 8183 | 593 | m_ins_nodes(), | |
| 8184 | 593 | m_sql_stat_start(), | |
| 8185 | 593 | m_trx_ids(), | |
| 8186 | 593 | m_num_new_parts(parts) {} | |
| 8187 | |||
| 8188 | /** Destructor */ | ||
| 8189 | ~Altered_partitions(); | ||
| 8190 | |||
| 8191 | /** Initialize the object. | ||
| 8192 | @return false on success | ||
| 8193 | @retval true on failure */ | ||
| 8194 | bool initialize(); | ||
| 8195 | |||
| 8196 | /** Open and set currently used partition. | ||
| 8197 | @param[in] new_part_id Partition id to set. | ||
| 8198 | @param[in,out] part Internal table object to use. */ | ||
| 8199 | 1503 | void set_part(ulint new_part_id, dict_table_t *part) { | |
| 8200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1503 times.
|
1503 | ut_ad(m_new_table_parts[new_part_id] == nullptr); |
| 8201 | 1503 | m_new_table_parts[new_part_id] = part; | |
| 8202 | 1503 | part->skip_alter_undo = true; | |
| 8203 | 1503 | m_sql_stat_start.set(new_part_id); | |
| 8204 | 1503 | } | |
| 8205 | |||
| 8206 | /** Get lower level internal table object for partition. | ||
| 8207 | @param[in] part_id Partition id. | ||
| 8208 | @return Lower level internal table object for the partition id. */ | ||
| 8209 | 2687 | dict_table_t *part(uint part_id) { | |
| 8210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2687 times.
|
2687 | ut_ad(part_id < m_num_new_parts); |
| 8211 | 2687 | return (m_new_table_parts[part_id]); | |
| 8212 | } | ||
| 8213 | |||
| 8214 | /** To write a row, set up prebuilt for using a specified partition. | ||
| 8215 | @param[in,out] prebuilt Prebuilt to update. | ||
| 8216 | @param[in] new_part_id Partition to use. */ | ||
| 8217 | 2682 | void prepare_write(row_prebuilt_t *prebuilt, uint new_part_id) const { | |
| 8218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2682 times.
|
2682 | ut_ad(m_new_table_parts[new_part_id]); |
| 8219 | 2682 | prebuilt->table = m_new_table_parts[new_part_id]; | |
| 8220 | 2682 | prebuilt->ins_node = m_ins_nodes[new_part_id]; | |
| 8221 | 2682 | prebuilt->trx_id = m_trx_ids[new_part_id]; | |
| 8222 | 2682 | prebuilt->sql_stat_start = m_sql_stat_start.test(new_part_id); | |
| 8223 | 2682 | } | |
| 8224 | |||
| 8225 | /** After a write, update cached values for a partition from prebuilt. | ||
| 8226 | @param[in,out] prebuilt Prebuilt to copy from. | ||
| 8227 | @param[in] new_part_id Partition id to copy. */ | ||
| 8228 | 2682 | void finish_write(row_prebuilt_t *prebuilt, uint new_part_id) { | |
| 8229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2682 times.
|
2682 | ut_ad(m_new_table_parts[new_part_id] == prebuilt->table); |
| 8230 | 2682 | m_ins_nodes[new_part_id] = prebuilt->ins_node; | |
| 8231 | 2682 | m_trx_ids[new_part_id] = prebuilt->trx_id; | |
| 8232 |
1/2✓ Branch 0 taken 2682 times.
✗ Branch 1 not taken.
|
2682 | if (!prebuilt->sql_stat_start) { |
| 8233 | 2682 | m_sql_stat_start.set(new_part_id, false); | |
| 8234 | } | ||
| 8235 | 2682 | } | |
| 8236 | |||
| 8237 | private: | ||
| 8238 | /** New partitions created during ADD(HASH/KEY)/COALESCE/REORGANIZE | ||
| 8239 | PARTITION. */ | ||
| 8240 | dict_table_t **m_new_table_parts; | ||
| 8241 | |||
| 8242 | /** Insert nodes per partition. */ | ||
| 8243 | ins_node_t **m_ins_nodes; | ||
| 8244 | |||
| 8245 | /** bytes for sql_stat_start bitset */ | ||
| 8246 | byte *m_bitset; | ||
| 8247 | |||
| 8248 | /** sql_stat_start per partition */ | ||
| 8249 | Sql_stat_start_parts m_sql_stat_start; | ||
| 8250 | |||
| 8251 | /** Trx id per partition. */ | ||
| 8252 | trx_id_t *m_trx_ids; | ||
| 8253 | |||
| 8254 | /** Number of new partitions. */ | ||
| 8255 | size_t m_num_new_parts; | ||
| 8256 | }; | ||
| 8257 | |||
| 8258 | /** Destructor */ | ||
| 8259 | 484 | Altered_partitions::~Altered_partitions() { | |
| 8260 |
1/2✓ Branch 0 taken 484 times.
✗ Branch 1 not taken.
|
484 | if (m_new_table_parts != nullptr) { |
| 8261 |
2/2✓ Branch 0 taken 1957 times.
✓ Branch 1 taken 484 times.
|
2441 | for (ulint i = 0; i < m_num_new_parts; i++) { |
| 8262 |
2/2✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 631 times.
|
1957 | if (m_new_table_parts[i] != nullptr) { |
| 8263 | 1326 | m_new_table_parts[i]->skip_alter_undo = false; | |
| 8264 | } | ||
| 8265 | } | ||
| 8266 | |||
| 8267 | 484 | ut::free(m_new_table_parts); | |
| 8268 | } | ||
| 8269 | |||
| 8270 |
1/2✓ Branch 0 taken 484 times.
✗ Branch 1 not taken.
|
484 | if (m_ins_nodes != nullptr) { |
| 8271 |
2/2✓ Branch 0 taken 1957 times.
✓ Branch 1 taken 484 times.
|
2441 | for (ulint i = 0; i < m_num_new_parts; i++) { |
| 8272 |
2/2✓ Branch 0 taken 771 times.
✓ Branch 1 taken 1186 times.
|
1957 | if (m_ins_nodes[i] != nullptr) { |
| 8273 | 771 | ins_node_t *ins = m_ins_nodes[i]; | |
| 8274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 771 times.
|
771 | ut_ad(ins->select == nullptr); |
| 8275 | 771 | que_graph_free_recursive(ins->select); | |
| 8276 | 771 | ins->select = nullptr; | |
| 8277 |
1/2✓ Branch 0 taken 771 times.
✗ Branch 1 not taken.
|
771 | if (ins->entry_sys_heap != nullptr) { |
| 8278 | 771 | mem_heap_free(ins->entry_sys_heap); | |
| 8279 | 771 | ins->entry_sys_heap = nullptr; | |
| 8280 | } | ||
| 8281 | } | ||
| 8282 | } | ||
| 8283 | |||
| 8284 | 484 | ut::free(m_ins_nodes); | |
| 8285 | } | ||
| 8286 | |||
| 8287 | 484 | ut::free(m_bitset); | |
| 8288 | 484 | ut::free(m_trx_ids); | |
| 8289 | 484 | } | |
| 8290 | |||
| 8291 | /** Initialize the object. | ||
| 8292 | @return false on success else true. */ | ||
| 8293 | 593 | bool Altered_partitions::initialize() { | |
| 8294 | 593 | size_t alloc_size = sizeof(*m_new_table_parts) * m_num_new_parts; | |
| 8295 | 593 | m_new_table_parts = static_cast<dict_table_t **>(ut::zalloc_withkey( | |
| 8296 | ut::make_psi_memory_key(mem_key_partitioning), alloc_size)); | ||
| 8297 | |||
| 8298 | 593 | alloc_size = sizeof(*m_ins_nodes) * m_num_new_parts; | |
| 8299 | 593 | m_ins_nodes = static_cast<ins_node_t **>(ut::zalloc_withkey( | |
| 8300 | ut::make_psi_memory_key(mem_key_partitioning), alloc_size)); | ||
| 8301 | |||
| 8302 | 593 | alloc_size = sizeof(*m_bitset) * UT_BITS_IN_BYTES(m_num_new_parts); | |
| 8303 | 593 | m_bitset = static_cast<byte *>(ut::zalloc_withkey( | |
| 8304 | ut::make_psi_memory_key(mem_key_partitioning), alloc_size)); | ||
| 8305 | |||
| 8306 | 593 | alloc_size = sizeof(*m_trx_ids) * m_num_new_parts; | |
| 8307 | 593 | m_trx_ids = static_cast<trx_id_t *>(ut::zalloc_withkey( | |
| 8308 | ut::make_psi_memory_key(mem_key_partitioning), alloc_size)); | ||
| 8309 | |||
| 8310 |
2/4✓ Branch 0 taken 593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 593 times.
✗ Branch 3 not taken.
|
593 | if (m_new_table_parts == nullptr || m_ins_nodes == nullptr || |
| 8311 |
2/4✓ Branch 0 taken 593 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 593 times.
|
593 | m_bitset == nullptr || m_trx_ids == nullptr) { |
| 8312 | ✗ | ut::free(m_new_table_parts); | |
| 8313 | ✗ | ut::free(m_ins_nodes); | |
| 8314 | ✗ | ut::free(m_bitset); | |
| 8315 | ✗ | ut::free(m_trx_ids); | |
| 8316 | |||
| 8317 | ✗ | return (true); | |
| 8318 | } | ||
| 8319 | |||
| 8320 | 593 | m_sql_stat_start.init(m_bitset, UT_BITS_IN_BYTES(m_num_new_parts)); | |
| 8321 | |||
| 8322 | 593 | return (false); | |
| 8323 | } | ||
| 8324 | |||
| 8325 | /** Class(interface) which manages the operations for partitions of states | ||
| 8326 | in different categories during ALTER PARTITION. There are four categories | ||
| 8327 | for now: | ||
| 8328 | 1. normal: mapping to PART_NORMAL, which means the partition is not changed | ||
| 8329 | 2. add: mapping to PART_TO_BE_ADDED | ||
| 8330 | 3. drop: mapping to PART_TO_BE_DROPPED, PART_TO_BE_REORGED | ||
| 8331 | and PART_REORGED_DROPPED | ||
| 8332 | 4. change: mapping to PART_CHANGED */ | ||
| 8333 | class alter_part { | ||
| 8334 | public: | ||
| 8335 | /** Virtual destructor */ | ||
| 8336 | 9484 | virtual ~alter_part() = default; | |
| 8337 | |||
| 8338 | /** Return the partition id */ | ||
| 8339 | 6181 | virtual uint part_id() const { return (m_part_id); } | |
| 8340 | |||
| 8341 | /** Return the partition state */ | ||
| 8342 | 9678 | virtual partition_state state() const { return (m_state); } | |
| 8343 | |||
| 8344 | /** Get the InnoDB table object for newly created partition | ||
| 8345 | if applicable | ||
| 8346 | @return the InnoDB table object or nullptr if not applicable */ | ||
| 8347 | 3665 | dict_table_t *new_table() { return (m_new); } | |
| 8348 | |||
| 8349 | /** Set the freed old partition to nullptr to avoid dangling pointer | ||
| 8350 | @param check_in_cache whether we need to check table in cache | ||
| 8351 | @param part_name Partitioned table name .*/ | ||
| 8352 | 1978 | inline void free_old_part(bool check_in_cache, const char *part_name) { | |
| 8353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1978 times.
|
1978 | if (check_in_cache) { |
| 8354 | ✗ | dict_sys_mutex_enter(); | |
| 8355 | |||
| 8356 | ✗ | if (!dict_table_check_if_in_cache_low(part_name)) { | |
| 8357 | ✗ | *m_old = nullptr; | |
| 8358 | } | ||
| 8359 | |||
| 8360 | ✗ | dict_sys_mutex_exit(); | |
| 8361 | |||
| 8362 | } else { | ||
| 8363 | 1978 | *m_old = nullptr; | |
| 8364 | } | ||
| 8365 | 1978 | } | |
| 8366 | |||
| 8367 | /** Prepare | ||
| 8368 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8369 | @param[in] old_part the stored old partition or nullptr | ||
| 8370 | if no corresponding one exists | ||
| 8371 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8372 | if no corresponding one exists | ||
| 8373 | @return 0 or error number */ | ||
| 8374 | 1384 | virtual int prepare(TABLE *altered_table [[maybe_unused]], | |
| 8375 | const dd::Partition *old_part [[maybe_unused]], | ||
| 8376 | dd::Partition *new_part [[maybe_unused]]) { | ||
| 8377 | 1384 | return (0); | |
| 8378 | } | ||
| 8379 | |||
| 8380 | /** Try to commit | ||
| 8381 | @param[in] table Table definition before the ALTER | ||
| 8382 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8383 | @param[in] old_part the stored old partition or nullptr | ||
| 8384 | if no corresponding one exists | ||
| 8385 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8386 | if no corresponding one exists | ||
| 8387 | @return 0 or error number */ | ||
| 8388 | ✗ | virtual int try_commit(const TABLE *table [[maybe_unused]], | |
| 8389 | TABLE *altered_table [[maybe_unused]], | ||
| 8390 | const dd::Partition *old_part [[maybe_unused]], | ||
| 8391 | dd::Partition *new_part [[maybe_unused]]) { | ||
| 8392 | ✗ | return (0); | |
| 8393 | } | ||
| 8394 | |||
| 8395 | /** Rollback */ | ||
| 8396 | 174 | virtual void rollback() { return; } | |
| 8397 | |||
| 8398 | protected: | ||
| 8399 | /** Constructor | ||
| 8400 | @param[in,out] trx InnoDB transaction, nullptr if not used | ||
| 8401 | @param[in] part_id Partition id in the table. This could | ||
| 8402 | be partition id for either old table | ||
| 8403 | or new table, callers should remember | ||
| 8404 | which one is applicable | ||
| 8405 | @param[in] state Partition state of the partition on | ||
| 8406 | which this class will do operations. | ||
| 8407 | If this is for one partition in new | ||
| 8408 | table, the partition state is the same | ||
| 8409 | for both the new partition and the | ||
| 8410 | corresponding old partition | ||
| 8411 | @param[in] table_name Partitioned table name, in the | ||
| 8412 | form of db/table, which considers | ||
| 8413 | the charset | ||
| 8414 | @param[in,out] old InnoDB table object for old partition, | ||
| 8415 | default is nullptr, which means there | ||
| 8416 | is no corresponding object */ | ||
| 8417 | 5261 | alter_part(trx_t *trx, uint part_id, partition_state state, | |
| 8418 | const char *table_name, dict_table_t **old) | ||
| 8419 | 5261 | : m_trx(trx), | |
| 8420 | 5261 | m_part_id(part_id), | |
| 8421 | 5261 | m_state(state), | |
| 8422 | 5261 | m_table_name(table_name), | |
| 8423 | 5261 | m_old(old), | |
| 8424 | 5261 | m_new(nullptr) {} | |
| 8425 | |||
| 8426 | /** Build the partition name for specified partition | ||
| 8427 | @param[in] dd_part dd::Partition | ||
| 8428 | @param[in] temp True if this is a temporary name | ||
| 8429 | @param[out] name Partition name buffer of length FN_REFLEN | ||
| 8430 | @return true if successful. */ | ||
| 8431 | bool build_partition_name(const dd::Partition *dd_part, bool temp, | ||
| 8432 | char *name); | ||
| 8433 | |||
| 8434 | /** Create a new partition | ||
| 8435 | @param[in] part_table partition table | ||
| 8436 | @param[in] part_name Partition name, including db/table | ||
| 8437 | @param[in,out] dd_part dd::Partition | ||
| 8438 | @param[in] table Table format | ||
| 8439 | @param[in] tablespace Tablespace of this partition, | ||
| 8440 | if length is 0, it means no | ||
| 8441 | tablespace specified | ||
| 8442 | @param[in] file_per_table Current value of innodb_file_per_table | ||
| 8443 | @param[in] autoinc Next AUTOINC value to use | ||
| 8444 | @param[in] autoextend_size Value of AUTOEXTEND_SIZE for this tablespace | ||
| 8445 | @return 0 or error number */ | ||
| 8446 | int create(const dd::Table *part_table, const char *part_name, | ||
| 8447 | dd::Partition *dd_part, TABLE *table, const char *tablespace, | ||
| 8448 | bool file_per_table, uint64_t autoinc, uint64_t autoextend_size); | ||
| 8449 | |||
| 8450 | protected: | ||
| 8451 | /** InnoDB transaction, nullptr if not used */ | ||
| 8452 | trx_t *const m_trx; | ||
| 8453 | |||
| 8454 | /** Partition id in the table. This could be partition id for | ||
| 8455 | either old table or new table, callers should remember which one | ||
| 8456 | is applicable */ | ||
| 8457 | uint m_part_id; | ||
| 8458 | |||
| 8459 | /** Partition state of the partition on which this class will | ||
| 8460 | do operations. If this is for one partition in new table, the | ||
| 8461 | partition state is the same for both the new partition and the | ||
| 8462 | corresponding old partition */ | ||
| 8463 | partition_state m_state; | ||
| 8464 | |||
| 8465 | /** Partitioned table name, in form of ./db/table, which already | ||
| 8466 | considers the charset */ | ||
| 8467 | const char *m_table_name; | ||
| 8468 | |||
| 8469 | /** The InnoDB table object for old partition */ | ||
| 8470 | dict_table_t **m_old; | ||
| 8471 | |||
| 8472 | /** The InnoDB table object for newly created partition */ | ||
| 8473 | dict_table_t *m_new; | ||
| 8474 | }; | ||
| 8475 | |||
| 8476 | 4572 | bool alter_part::build_partition_name(const dd::Partition *dd_part, bool temp, | |
| 8477 | char *name) { | ||
| 8478 |
2/4✓ Branch 0 taken 4572 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4572 times.
|
4572 | if (!normalize_table_name(name, m_table_name)) { |
| 8479 | /* purecov: begin inspected */ | ||
| 8480 | ✗ | ut_d(ut_error); | |
| 8481 | ut_o(return (false)); | ||
| 8482 | /* purecov: end */ | ||
| 8483 | } | ||
| 8484 | |||
| 8485 | 4572 | std::string partition; | |
| 8486 | /* Build the partition name. */ | ||
| 8487 |
1/2✓ Branch 0 taken 4572 times.
✗ Branch 1 not taken.
|
4572 | dict_name::build_partition(dd_part, partition); |
| 8488 | |||
| 8489 | 4572 | std::string partition_name; | |
| 8490 | /* Build the partitioned table name. */ | ||
| 8491 |
3/6✓ Branch 0 taken 4572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4572 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4572 times.
✗ Branch 5 not taken.
|
4572 | dict_name::build_table("", name, partition, temp, false, partition_name); |
| 8492 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4572 times.
|
4572 | ut_ad(partition_name.length() < FN_REFLEN); |
| 8493 | |||
| 8494 | /* Copy partition table name. */ | ||
| 8495 |
1/2✓ Branch 0 taken 4572 times.
✗ Branch 1 not taken.
|
4572 | auto name_len = partition_name.copy(name, FN_REFLEN - 1); |
| 8496 | 4572 | name[name_len] = '\0'; | |
| 8497 | |||
| 8498 | 4572 | return (true); | |
| 8499 | 4572 | } | |
| 8500 | |||
| 8501 | 1702 | int alter_part::create(const dd::Table *old_part_table, const char *part_name, | |
| 8502 | dd::Partition *dd_part, TABLE *table, | ||
| 8503 | const char *tablespace, bool file_per_table, | ||
| 8504 | uint64_t autoinc, uint64_t autoextend_size) { | ||
| 8505 |
4/6✓ Branch 0 taken 876 times.
✓ Branch 1 taken 826 times.
✓ Branch 2 taken 876 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1702 times.
|
1702 | ut_ad(m_state == PART_TO_BE_ADDED || m_state == PART_CHANGED); |
| 8506 | |||
| 8507 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
1702 | dd::Table &dd_table = dd_part->table(); |
| 8508 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
1702 | dd::Properties &options = dd_table.options(); |
| 8509 | uint32_t key_block_size; | ||
| 8510 |
3/6✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1702 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1702 times.
|
1702 | ut_ad(options.exists("key_block_size")); |
| 8511 |
2/4✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1702 times.
✗ Branch 3 not taken.
|
1702 | options.get("key_block_size", &key_block_size); |
| 8512 | |||
| 8513 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
1702 | dd::Properties &part_options = dd_part->options(); |
| 8514 | 1702 | dd::String_type data_file_name; | |
| 8515 |
3/4✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1676 times.
|
1702 | if (part_options.exists(data_file_name_key)) |
| 8516 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | (void)part_options.get(data_file_name_key, &data_file_name); |
| 8517 | /* index_file_name is not allowed for now */ | ||
| 8518 | char full_path[FN_REFLEN]; | ||
| 8519 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1676 times.
|
1702 | if (!data_file_name.empty()) { |
| 8520 | /* Have to append the postfix table name, to make it work */ | ||
| 8521 | 26 | const char *name = strrchr(part_name, '/'); | |
| 8522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | ut_ad(name != nullptr); |
| 8523 | 26 | size_t len = data_file_name.length(); | |
| 8524 | 26 | strcpy(full_path, data_file_name.c_str()); | |
| 8525 | 26 | full_path[len] = OS_PATH_SEPARATOR; | |
| 8526 | 26 | strcpy(full_path + len + 1, name + 1); | |
| 8527 | } | ||
| 8528 | |||
| 8529 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
1702 | HA_CREATE_INFO create_info; |
| 8530 |
1/2✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
|
1702 | update_create_info_from_table(&create_info, table); |
| 8531 | 1702 | create_info.auto_increment_value = autoinc; | |
| 8532 | 1702 | create_info.key_block_size = key_block_size; | |
| 8533 |
2/2✓ Branch 0 taken 1676 times.
✓ Branch 1 taken 26 times.
|
1702 | create_info.data_file_name = data_file_name.empty() ? nullptr : full_path; |
| 8534 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1666 times.
|
1702 | create_info.tablespace = tablespace[0] == '\0' ? nullptr : tablespace; |
| 8535 | 1702 | create_info.m_implicit_tablespace_autoextend_size = autoextend_size; | |
| 8536 | |||
| 8537 | /* The below check is the same as for CREATE TABLE, but since we are | ||
| 8538 | doing an alter here it will not trigger the check in | ||
| 8539 | create_option_tablespace_is_valid(). */ | ||
| 8540 | 1702 | if (tablespace_is_shared_space(&create_info) && | |
| 8541 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 1702 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1702 times.
|
1702 | create_info.data_file_name != nullptr && |
| 8542 | ✗ | create_info.data_file_name[0] != '\0') { | |
| 8543 | ✗ | my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION, | |
| 8544 | "InnoDB: DATA DIRECTORY cannot be used" | ||
| 8545 | " with a TABLESPACE assignment.", | ||
| 8546 | MYF(0)); | ||
| 8547 | ✗ | return (HA_WRONG_CREATE_OPTION); | |
| 8548 | } | ||
| 8549 | |||
| 8550 | 5031 | return (innobase_basic_ddl::create_impl<dd::Partition>( | |
| 8551 |
2/4✓ Branch 0 taken 1702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1627 times.
✗ Branch 3 not taken.
|
1702 | current_thd, part_name, table, &create_info, dd_part, file_per_table, |
| 8552 | 1627 | false, false, 0, 0, old_part_table)); | |
| 8553 | 1627 | } | |
| 8554 | |||
| 8555 | typedef std::vector<alter_part *, ut::allocator<alter_part *>> alter_part_array; | ||
| 8556 | |||
| 8557 | /** Construct all necessary alter_part_* objects according to the given | ||
| 8558 | partition states in both old and new tables */ | ||
| 8559 | class alter_part_factory { | ||
| 8560 | public: | ||
| 8561 | /** Constructor | ||
| 8562 | @param[in,out] trx Transaction | ||
| 8563 | @param[in] ha_alter_info ALTER Information | ||
| 8564 | @param[in,out] part_share Innopart share | ||
| 8565 | @param[in] old_part_info Partition info of the table before | ||
| 8566 | ALTER TABLE */ | ||
| 8567 | 943 | alter_part_factory(trx_t *trx, const Alter_inplace_info *ha_alter_info, | |
| 8568 | Ha_innopart_share *part_share, | ||
| 8569 | partition_info *old_part_info) | ||
| 8570 | 943 | : m_trx(trx), | |
| 8571 | 943 | m_part_share(part_share), | |
| 8572 | 943 | m_ha_alter_info(ha_alter_info), | |
| 8573 | 943 | m_old_part_info(old_part_info), | |
| 8574 | 943 | m_file_per_table(srv_file_per_table) {} | |
| 8575 | |||
| 8576 | /** Destructor */ | ||
| 8577 | ~alter_part_factory() = default; | ||
| 8578 | |||
| 8579 | /** Create the alter_part_* objects according to the given | ||
| 8580 | partition states | ||
| 8581 | @param[in,out] to_drop To store the alter_part_* objects | ||
| 8582 | for partitions to be dropped | ||
| 8583 | @param[in,out] all_news To store the alter_part_* objects | ||
| 8584 | for partitions in table after | ||
| 8585 | ALTER TABLE | ||
| 8586 | @return false On success | ||
| 8587 | @retval true On failure */ | ||
| 8588 | 943 | bool create(alter_part_array &to_drop, alter_part_array &all_news) { | |
| 8589 | 943 | to_drop.clear(); | |
| 8590 | 943 | all_news.clear(); | |
| 8591 | |||
| 8592 |
2/2✓ Branch 0 taken 719 times.
✓ Branch 1 taken 224 times.
|
943 | if (!(m_ha_alter_info->handler_flags & |
| 8593 | Alter_inplace_info::REORGANIZE_PARTITION)) { | ||
| 8594 | 719 | return (create_for_non_reorg(to_drop, all_news)); | |
| 8595 | } else { | ||
| 8596 | 224 | return (create_for_reorg(to_drop, all_news)); | |
| 8597 | } | ||
| 8598 | } | ||
| 8599 | |||
| 8600 | private: | ||
| 8601 | bool create_for_reorg(alter_part_array &to_drop, alter_part_array &all_news); | ||
| 8602 | bool create_for_non_reorg(alter_part_array &to_drop, | ||
| 8603 | alter_part_array &all_news); | ||
| 8604 | bool create_new_checking_conflict(partition_element *new_part, | ||
| 8605 | uint &new_part_id, | ||
| 8606 | alter_part_array &all_news); | ||
| 8607 | bool create_old_checking_conflict(partition_element *old_part, | ||
| 8608 | uint &old_part_id, | ||
| 8609 | alter_part_array &to_drop); | ||
| 8610 | bool is_conflict(const partition_element *new_part, | ||
| 8611 | const partition_element *old_part); | ||
| 8612 | bool create_one(alter_part_array &array, partition_element *part, | ||
| 8613 | uint &part_id, uint old_part_id, partition_state state, | ||
| 8614 | bool conflict); | ||
| 8615 | alter_part *create_one_low(uint &part_id, uint old_part_id, | ||
| 8616 | partition_state state, const char *tablespace, | ||
| 8617 | bool conflict); | ||
| 8618 | |||
| 8619 | private: | ||
| 8620 | /** InnoDB transaction */ | ||
| 8621 | trx_t *const m_trx; | ||
| 8622 | |||
| 8623 | /** InnoDB partition specific Handler_share */ | ||
| 8624 | Ha_innopart_share *const m_part_share; | ||
| 8625 | |||
| 8626 | /** ALTER information */ | ||
| 8627 | const Alter_inplace_info *const m_ha_alter_info; | ||
| 8628 | |||
| 8629 | /** Partition info of the table before ALTER TABLE */ | ||
| 8630 | partition_info *const m_old_part_info; | ||
| 8631 | |||
| 8632 | /** Current innodb_file_per_table value */ | ||
| 8633 | bool m_file_per_table; | ||
| 8634 | }; | ||
| 8635 | |||
| 8636 | /** Helper class for in-place alter partitions, see handler.h */ | ||
| 8637 | class alter_parts : public inplace_alter_handler_ctx { | ||
| 8638 | public: | ||
| 8639 | /** Constructor | ||
| 8640 | @param[in,out] trx InnoDB transaction | ||
| 8641 | @param[in,out] part_share Innopart share | ||
| 8642 | @param[in] ha_alter_info ALTER information | ||
| 8643 | @param[in] old_part_info Partition info of the table before | ||
| 8644 | ALTER TABLE | ||
| 8645 | @param[in,out] new_partitions Altered partition helper */ | ||
| 8646 | 943 | alter_parts(trx_t *trx, Ha_innopart_share *part_share, | |
| 8647 | const Alter_inplace_info *ha_alter_info, | ||
| 8648 | partition_info *old_part_info, Altered_partitions *new_partitions) | ||
| 8649 | 1886 | : m_trx(trx), | |
| 8650 | 943 | m_part_share(part_share), | |
| 8651 | 943 | m_ha_alter_info(ha_alter_info), | |
| 8652 | 943 | m_new_partitions(new_partitions), | |
| 8653 | 943 | m_factory(trx, ha_alter_info, part_share, old_part_info), | |
| 8654 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
943 | m_news(), |
| 8655 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
1886 | m_to_drop() {} |
| 8656 | |||
| 8657 | /** Destructor */ | ||
| 8658 | ~alter_parts() override; | ||
| 8659 | |||
| 8660 | /** Create the to be created partitions and update internal | ||
| 8661 | structures with concurrent writes blocked, while preparing | ||
| 8662 | ALTER TABLE. | ||
| 8663 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 8664 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 8665 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8666 | @return 0 or error number, my_error() should be called by callers */ | ||
| 8667 | int prepare(const dd::Table &old_dd_tab, dd::Table &new_dd_tab, | ||
| 8668 | TABLE *altered_table); | ||
| 8669 | |||
| 8670 | /** Notify the storage engine that the changes made during | ||
| 8671 | prepare_inplace_alter_table() and inplace_alter_table() | ||
| 8672 | will be rolled back for all the partitions. */ | ||
| 8673 | void rollback(); | ||
| 8674 | |||
| 8675 | /** Try to commit the changes made during prepare_inplace_alter_table() | ||
| 8676 | inside the storage engine. This is protected by MDL_EXCLUSIVE. | ||
| 8677 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 8678 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 8679 | @param[in] table Table definition before the ALTER | ||
| 8680 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8681 | @return 0 or error number, my_error() should be called by callers */ | ||
| 8682 | int try_commit(const dd::Table &old_dd_tab, dd::Table &new_dd_tab, | ||
| 8683 | const TABLE *table, TABLE *altered_table); | ||
| 8684 | |||
| 8685 | /** Determine if this is an ALTER TABLE ... PARTITION operation | ||
| 8686 | @param[in] ha_alter_info thd DDL operation | ||
| 8687 | @return whether it is a such kind of operation */ | ||
| 8688 | 11803 | static inline bool apply_to(const Alter_inplace_info *ha_alter_info) { | |
| 8689 | 11803 | return ((ha_alter_info->handler_flags & OPERATIONS) != 0); | |
| 8690 | } | ||
| 8691 | |||
| 8692 | /** Determine if copying data between partitions is necessary | ||
| 8693 | @param[in] ha_alter_info thd DDL operation | ||
| 8694 | @return whether it is necessary to copy data */ | ||
| 8695 | 4144 | static inline bool need_copy(const Alter_inplace_info *ha_alter_info) { | |
| 8696 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4144 times.
|
4144 | ut_ad(apply_to(ha_alter_info)); |
| 8697 | |||
| 8698 | /* Basically, only DROP PARTITION, ADD PARTITION for RANGE/LIST | ||
| 8699 | partitions don't require copying data between partitions */ | ||
| 8700 |
2/2✓ Branch 0 taken 1143 times.
✓ Branch 1 taken 3001 times.
|
4144 | if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_PARTITION) { |
| 8701 |
2/2✓ Branch 0 taken 389 times.
✓ Branch 1 taken 754 times.
|
1143 | switch (ha_alter_info->modified_part_info->part_type) { |
| 8702 | 389 | case partition_type::RANGE: | |
| 8703 | case partition_type::LIST: | ||
| 8704 | 389 | return (false); | |
| 8705 | 754 | default: | |
| 8706 | 754 | break; | |
| 8707 | } | ||
| 8708 | } | ||
| 8709 | |||
| 8710 | return ( | ||
| 8711 | 3755 | !(ha_alter_info->handler_flags & (Alter_inplace_info::DROP_PARTITION))); | |
| 8712 | } | ||
| 8713 | |||
| 8714 | private: | ||
| 8715 | /** Initialize the m_news and m_to_drop array here | ||
| 8716 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 8717 | @param[in] new_dd_tab dd::Table after ALTER TABLE | ||
| 8718 | @retval true if success | ||
| 8719 | @retval false on failure */ | ||
| 8720 | bool prepare_alter_part(const dd::Table &old_dd_tab, dd::Table &new_dd_tab); | ||
| 8721 | |||
| 8722 | /** Prepare or commit for all the partitions in table after ALTER TABLE | ||
| 8723 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 8724 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 8725 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8726 | @param[in] prepare true if it's in prepare phase, | ||
| 8727 | false if it's in commit phase | ||
| 8728 | @return 0 or error number */ | ||
| 8729 | int prepare_or_commit_for_new(const dd::Table &old_dd_tab, | ||
| 8730 | dd::Table &new_dd_tab, TABLE *altered_table, | ||
| 8731 | bool prepare); | ||
| 8732 | |||
| 8733 | /** Prepare or commit for all the partitions in table before ALTER TABLE | ||
| 8734 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 8735 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8736 | @param[in] prepare true if it's in prepare phase, | ||
| 8737 | false if it's in commit phase | ||
| 8738 | @return 0 or error number */ | ||
| 8739 | int prepare_or_commit_for_old(const dd::Table &old_dd_tab, | ||
| 8740 | TABLE *altered_table, bool prepare); | ||
| 8741 | |||
| 8742 | public: | ||
| 8743 | /** Operations that the native partitioning can perform inplace */ | ||
| 8744 | static constexpr Alter_inplace_info::HA_ALTER_FLAGS OPERATIONS = | ||
| 8745 | Alter_inplace_info::ADD_PARTITION | Alter_inplace_info::DROP_PARTITION | | ||
| 8746 | Alter_inplace_info::ALTER_REBUILD_PARTITION | | ||
| 8747 | Alter_inplace_info::COALESCE_PARTITION | | ||
| 8748 | Alter_inplace_info::REORGANIZE_PARTITION; | ||
| 8749 | |||
| 8750 | private: | ||
| 8751 | /** InnoDB transaction */ | ||
| 8752 | trx_t *const m_trx; | ||
| 8753 | |||
| 8754 | /** InnoDB partition specific Handler_share */ | ||
| 8755 | Ha_innopart_share *const m_part_share; | ||
| 8756 | |||
| 8757 | /** Operation being performed */ | ||
| 8758 | const Alter_inplace_info *const m_ha_alter_info; | ||
| 8759 | |||
| 8760 | /** New partitions helper */ | ||
| 8761 | Altered_partitions *const m_new_partitions; | ||
| 8762 | |||
| 8763 | /** alter_part factory which creates all the necessary alter_part_* */ | ||
| 8764 | alter_part_factory m_factory; | ||
| 8765 | |||
| 8766 | /** The alter_part array for all the newly created partitions */ | ||
| 8767 | alter_part_array m_news; | ||
| 8768 | |||
| 8769 | /** The alter_part array for all the to be dropped partitions */ | ||
| 8770 | alter_part_array m_to_drop; | ||
| 8771 | }; | ||
| 8772 | |||
| 8773 | /** Class which handles the partition of state PART_NORMAL. | ||
| 8774 | See comments for alter_part_factory::create_for_reorg | ||
| 8775 | and alter_part_factory::create_for_non_reorg. */ | ||
| 8776 | class alter_part_normal : public alter_part { | ||
| 8777 | public: | ||
| 8778 | /** Constructor | ||
| 8779 | @param[in] part_id Partition id in the table. This could | ||
| 8780 | be partition id for either old table | ||
| 8781 | or new table, callers should remember | ||
| 8782 | which one is applicable | ||
| 8783 | @param[in] state Partition state of the partition on | ||
| 8784 | which this class will do operations. | ||
| 8785 | If this is for one partition in new | ||
| 8786 | table, the partition state is the same | ||
| 8787 | for both the new partition and the | ||
| 8788 | corresponding old partition | ||
| 8789 | @param[in,out] old InnoDB table object for old partition, | ||
| 8790 | default is nullptr, which means there | ||
| 8791 | is no corresponding object */ | ||
| 8792 | 2095 | alter_part_normal(uint part_id, partition_state state, dict_table_t **old) | |
| 8793 | 2095 | : /* Table name is not used in this class, so pass a fake | |
| 8794 | one */ | ||
| 8795 | 2095 | alter_part(nullptr, part_id, state, (*old)->name.m_name, old) {} | |
| 8796 | |||
| 8797 | /** Destructor */ | ||
| 8798 | 4050 | ~alter_part_normal() override = default; | |
| 8799 | |||
| 8800 | /** Prepare | ||
| 8801 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8802 | @param[in] old_part the stored old partition or nullptr | ||
| 8803 | if no corresponding one exists | ||
| 8804 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8805 | if no corresponding one exists | ||
| 8806 | @return 0 or error number */ | ||
| 8807 | 2095 | int prepare(TABLE *altered_table [[maybe_unused]], | |
| 8808 | const dd::Partition *old_part, dd::Partition *new_part) override { | ||
| 8809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2095 times.
|
2095 | ut_ad(old_part->name() == new_part->name()); |
| 8810 | |||
| 8811 | 2095 | dd_copy_private<dd::Partition>(*new_part, *old_part); | |
| 8812 | |||
| 8813 | 2095 | return (0); | |
| 8814 | } | ||
| 8815 | |||
| 8816 | /** Try to commit | ||
| 8817 | @param[in] table Table definition before the ALTER | ||
| 8818 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8819 | @param[in] old_part the stored old partition or nullptr | ||
| 8820 | if no corresponding one exists | ||
| 8821 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8822 | if no corresponding one exists | ||
| 8823 | @return 0 or error number */ | ||
| 8824 | 1872 | int try_commit(const TABLE *table [[maybe_unused]], | |
| 8825 | TABLE *altered_table [[maybe_unused]], | ||
| 8826 | const dd::Partition *old_part [[maybe_unused]], | ||
| 8827 | dd::Partition *new_part [[maybe_unused]]) override { | ||
| 8828 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1872 times.
|
1872 | ut_ad(m_old != nullptr); |
| 8829 | |||
| 8830 | 1872 | btr_drop_ahi_for_table(*m_old); | |
| 8831 | |||
| 8832 | 1872 | dict_sys_mutex_enter(); | |
| 8833 | 1872 | dd_table_close(*m_old, nullptr, nullptr, true); | |
| 8834 | 1872 | dict_table_remove_from_cache(*m_old); | |
| 8835 | 1872 | *m_old = nullptr; | |
| 8836 | 1872 | dict_sys_mutex_exit(); | |
| 8837 | 1872 | return (0); | |
| 8838 | } | ||
| 8839 | }; | ||
| 8840 | |||
| 8841 | /** Class which handles the partition of the state PART_TO_BE_ADDED. | ||
| 8842 | See comments for alter_part_factory::create_for_reorg | ||
| 8843 | and alter_part_factory::create_for_non_reorg. */ | ||
| 8844 | class alter_part_add : public alter_part { | ||
| 8845 | public: | ||
| 8846 | /** Constructor | ||
| 8847 | @param[in] part_id Partition id in the table. This could | ||
| 8848 | be partition id for either old table | ||
| 8849 | or new table, callers should remember | ||
| 8850 | which one is applicable | ||
| 8851 | @param[in] state Partition state of the partition on | ||
| 8852 | which this class will do operations. | ||
| 8853 | If this is for one partition in new | ||
| 8854 | table, the partition state is the same | ||
| 8855 | for both the new partition and the | ||
| 8856 | corresponding old partition | ||
| 8857 | @param[in] table_name Partitioned table name, in the form | ||
| 8858 | of db/table, which already considers | ||
| 8859 | the charset | ||
| 8860 | @param[in] tablespace Tablespace specified explicitly | ||
| 8861 | @param[in,out] trx InnoDB transaction | ||
| 8862 | @param[in] ha_alter_info ALTER information | ||
| 8863 | @param[in] file_per_table Current value of innodb_file_per_table | ||
| 8864 | @param[in] autoinc Next autoinc value to use | ||
| 8865 | @param[in] conflict True if there is already a partition | ||
| 8866 | table with the same name */ | ||
| 8867 | 888 | alter_part_add(uint part_id, partition_state state, const char *table_name, | |
| 8868 | const char *tablespace, trx_t *trx, | ||
| 8869 | const Alter_inplace_info *ha_alter_info, bool file_per_table, | ||
| 8870 | uint64_t autoinc, bool conflict) | ||
| 8871 | 888 | : alter_part(trx, part_id, state, table_name, nullptr), | |
| 8872 | 888 | m_ha_alter_info(ha_alter_info), | |
| 8873 | 888 | m_file_per_table(file_per_table), | |
| 8874 | 888 | m_autoinc(autoinc), | |
| 8875 | 888 | m_conflict(conflict) { | |
| 8876 |
3/4✓ Branch 0 taken 50 times.
✓ Branch 1 taken 838 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
|
888 | if (tablespace == nullptr || tablespace[0] == '\0') { |
| 8877 | 838 | m_tablespace[0] = '\0'; | |
| 8878 | } else { | ||
| 8879 | 50 | strcpy(m_tablespace, tablespace); | |
| 8880 | } | ||
| 8881 | 888 | } | |
| 8882 | |||
| 8883 | /** Destructor */ | ||
| 8884 | 1482 | ~alter_part_add() override = default; | |
| 8885 | |||
| 8886 | /** Prepare | ||
| 8887 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8888 | @param[in] old_part the stored old partition or nullptr | ||
| 8889 | if no corresponding one exists | ||
| 8890 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8891 | if no corresponding one exists | ||
| 8892 | @return 0 or error number */ | ||
| 8893 | 834 | int prepare(TABLE *altered_table, const dd::Partition *old_part, | |
| 8894 | dd::Partition *new_part) override { | ||
| 8895 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 834 times.
|
834 | ut_ad(old_part != nullptr); |
| 8896 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 834 times.
|
834 | ut_ad(new_part != nullptr); |
| 8897 | char part_name[FN_REFLEN]; | ||
| 8898 | |||
| 8899 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 826 times.
|
834 | if (is_shared_tablespace(m_tablespace)) { |
| 8900 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION, |
| 8901 | PARTITION_IN_SHARED_TABLESPACE, MYF(0)); | ||
| 8902 | 8 | return (HA_ERR_INTERNAL_ERROR); | |
| 8903 | } | ||
| 8904 | |||
| 8905 |
2/4✓ Branch 0 taken 826 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 826 times.
|
826 | if (!build_partition_name(new_part, need_rename(), part_name)) { |
| 8906 | ✗ | return (HA_ERR_TOO_LONG_PATH); /* purecov: inspected */ | |
| 8907 | } | ||
| 8908 | |||
| 8909 | /* Get the autoextend_size value from the old partition | ||
| 8910 | and set this value to the partition being added. */ | ||
| 8911 |
1/2✓ Branch 0 taken 826 times.
✗ Branch 1 not taken.
|
826 | const dd::Table &part_table = old_part->table(); |
| 8912 | |||
| 8913 | 826 | ulonglong autoextend_size{}; | |
| 8914 | |||
| 8915 |
2/4✓ Branch 0 taken 826 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 826 times.
✗ Branch 3 not taken.
|
826 | dd::get_implicit_tablespace_options(current_thd, &part_table, |
| 8916 | &autoextend_size); | ||
| 8917 | |||
| 8918 | int error = | ||
| 8919 |
3/4✓ Branch 0 taken 43 times.
✓ Branch 1 taken 783 times.
✓ Branch 2 taken 787 times.
✗ Branch 3 not taken.
|
826 | create(dd_table_has_instant_cols(part_table) ? &part_table : nullptr, |
| 8920 | 826 | part_name, new_part, altered_table, m_tablespace, | |
| 8921 |
1/2✓ Branch 0 taken 826 times.
✗ Branch 1 not taken.
|
826 | m_file_per_table, m_autoinc, autoextend_size); |
| 8922 | |||
| 8923 |
7/8✓ Branch 0 taken 783 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 783 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 664 times.
✓ Branch 5 taken 119 times.
✓ Branch 6 taken 664 times.
✓ Branch 7 taken 123 times.
|
787 | if (error == 0 && alter_parts::need_copy(m_ha_alter_info)) { |
| 8924 | /* If partition belongs to table with instant columns, copy instant | ||
| 8925 | metadata to new table DD */ | ||
| 8926 |
4/6✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 664 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 640 times.
|
664 | if (dd_table_has_row_versions(old_part->table())) { |
| 8927 |
3/6✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
|
24 | inherit_instant_metadata(&old_part->table(), &new_part->table()); |
| 8928 | } | ||
| 8929 | |||
| 8930 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | dict_sys_mutex_enter(); |
| 8931 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | m_new = dict_table_check_if_in_cache_low(part_name); |
| 8932 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 664 times.
|
664 | ut_ad(m_new != nullptr); |
| 8933 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | m_new->acquire(); |
| 8934 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | dict_table_ddl_release(m_new); |
| 8935 |
1/2✓ Branch 0 taken 664 times.
✗ Branch 1 not taken.
|
664 | dict_sys_mutex_exit(); |
| 8936 | |||
| 8937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 664 times.
|
664 | return (m_new == nullptr ? DB_TABLE_NOT_FOUND : 0); |
| 8938 | } | ||
| 8939 | |||
| 8940 | 123 | return (error); | |
| 8941 | } | ||
| 8942 | |||
| 8943 | /** Try to commit | ||
| 8944 | @param[in] table Table definition before the ALTER | ||
| 8945 | @param[in,out] altered_table Table definition after the ALTER | ||
| 8946 | @param[in] old_part the stored old partition or nullptr | ||
| 8947 | if no corresponding one exists | ||
| 8948 | @param[in,out] new_part the stored new partition or nullptr | ||
| 8949 | if no corresponding one exists | ||
| 8950 | @return 0 or error number */ | ||
| 8951 | 713 | int try_commit(const TABLE *table [[maybe_unused]], | |
| 8952 | TABLE *altered_table [[maybe_unused]], | ||
| 8953 | const dd::Partition *old_part [[maybe_unused]], | ||
| 8954 | dd::Partition *new_part) override { | ||
| 8955 | 713 | int error = 0; | |
| 8956 | |||
| 8957 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 650 times.
|
713 | if (need_rename()) { |
| 8958 | char old_name[FN_REFLEN]; | ||
| 8959 | char new_name[FN_REFLEN]; | ||
| 8960 | |||
| 8961 |
3/6✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
|
126 | if (build_partition_name(new_part, true, old_name) && |
| 8962 |
2/4✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
|
63 | build_partition_name(new_part, false, new_name)) { |
| 8963 | 60 | error = innobase_basic_ddl::rename_impl<dd::Partition>( | |
| 8964 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
63 | m_trx->mysql_thd, old_name, new_name, new_part, new_part, nullptr); |
| 8965 | |||
| 8966 | } else { | ||
| 8967 | ✗ | error = HA_ERR_TOO_LONG_PATH; /* purecov: inspected */ | |
| 8968 | } | ||
| 8969 | } | ||
| 8970 | |||
| 8971 |
2/2✓ Branch 0 taken 599 times.
✓ Branch 1 taken 111 times.
|
710 | if (m_new != nullptr) { |
| 8972 | 599 | dd_table_close(m_new, m_trx->mysql_thd, nullptr, false); | |
| 8973 | 599 | m_new = nullptr; | |
| 8974 | } | ||
| 8975 | |||
| 8976 | 710 | return (error); | |
| 8977 | } | ||
| 8978 | |||
| 8979 | /** Rollback */ | ||
| 8980 | 31 | void rollback() override { | |
| 8981 | /* Release the new table so that in post DDL, this table can be | ||
| 8982 | rolled back. */ | ||
| 8983 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 17 times.
|
31 | if (m_new != nullptr) { |
| 8984 | 14 | dd_table_close(m_new, m_trx->mysql_thd, nullptr, false); | |
| 8985 | 14 | m_new = nullptr; | |
| 8986 | } | ||
| 8987 | 31 | } | |
| 8988 | |||
| 8989 | private: | ||
| 8990 | /** Check if the new partition file needs a temporary name and | ||
| 8991 | should be renamed at last */ | ||
| 8992 | 1539 | bool need_rename() const { return (m_conflict); } | |
| 8993 | |||
| 8994 | /** Inherit instant metadata of dd::Table and dd::Columns belonging to it. | ||
| 8995 | This is used when a new partition is added as part of REORGANIZE partition. | ||
| 8996 | @param[in] source Source dd table | ||
| 8997 | @param[in,out] dest Destination dd table */ | ||
| 8998 | void inherit_instant_metadata(const dd::Table *source, dd::Table *dest); | ||
| 8999 | |||
| 9000 | private: | ||
| 9001 | /** ALTER information */ | ||
| 9002 | const Alter_inplace_info *m_ha_alter_info; | ||
| 9003 | |||
| 9004 | /** Current value of innodb_file_per_table */ | ||
| 9005 | const bool m_file_per_table; | ||
| 9006 | |||
| 9007 | /** Next AUTOINC value to use */ | ||
| 9008 | const uint64_t m_autoinc; | ||
| 9009 | |||
| 9010 | /** True if there is already a partition table with the same name */ | ||
| 9011 | const bool m_conflict; | ||
| 9012 | |||
| 9013 | /** Tablespace of this partition */ | ||
| 9014 | char m_tablespace[FN_REFLEN + 1]; | ||
| 9015 | }; | ||
| 9016 | |||
| 9017 | 24 | void alter_part_add::inherit_instant_metadata(const dd::Table *source, | |
| 9018 | dd::Table *dest) { | ||
| 9019 | 60 | auto add_dropped_column = [&](const dd::Column *column) { | |
| 9020 | 60 | const char *col_name = column->name().c_str(); | |
| 9021 | /* Add this column as an SE_HIDDEN column in dest table def */ | ||
| 9022 | 240 | dd::Column *new_column = dd_add_hidden_column( | |
| 9023 | 60 | dest, col_name, column->char_length(), column->type()); | |
| 9024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | ut_ad(new_column != nullptr); |
| 9025 | |||
| 9026 | /* Copy se private data */ | ||
| 9027 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | ut_ad(!column->se_private_data().empty()); |
| 9028 | 60 | new_column->se_private_data().clear(); | |
| 9029 | 60 | new_column->set_se_private_data(column->se_private_data()); | |
| 9030 | |||
| 9031 | 60 | new_column->set_nullable(column->is_nullable()); | |
| 9032 | 60 | new_column->set_char_length(column->char_length()); | |
| 9033 | 60 | new_column->set_numeric_scale(column->numeric_scale()); | |
| 9034 | 60 | new_column->set_unsigned(column->is_unsigned()); | |
| 9035 | 60 | new_column->set_collation_id(column->collation_id()); | |
| 9036 | 60 | new_column->set_type(column->type()); | |
| 9037 | /* Elements for enum columns */ | ||
| 9038 |
2/4✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
|
120 | if (column->type() == dd::enum_column_types::ENUM || |
| 9039 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | column->type() == dd::enum_column_types::SET) { |
| 9040 | ✗ | for (const auto *source_elem : column->elements()) { | |
| 9041 | ✗ | auto *elem_obj = new_column->add_element(); | |
| 9042 | ✗ | elem_obj->set_name(source_elem->name()); | |
| 9043 | } | ||
| 9044 | } | ||
| 9045 | 60 | }; | |
| 9046 | |||
| 9047 | /* Copy dd::Column instant metadata */ | ||
| 9048 |
6/10✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 204 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 204 times.
✓ Branch 9 taken 24 times.
|
228 | for (auto src_col : source->columns()) { |
| 9049 | dd::Column *dest_col = | ||
| 9050 |
2/4✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
|
204 | const_cast<dd::Column *>(dd_find_column(dest, src_col->name().c_str())); |
| 9051 | |||
| 9052 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 144 times.
|
204 | if (dest_col == nullptr) { |
| 9053 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | add_dropped_column(src_col); |
| 9054 |
3/6✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 60 times.
|
60 | ut_ad(nullptr != dd_find_column(dest, src_col->name().c_str())); |
| 9055 | 60 | continue; | |
| 9056 | } | ||
| 9057 | |||
| 9058 |
2/4✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
|
144 | if (dest_col->is_virtual()) { |
| 9059 | ✗ | continue; | |
| 9060 | } | ||
| 9061 | |||
| 9062 | 936 | auto fn = [&](const char *s, auto &value) { | |
| 9063 |
4/6✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 468 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 252 times.
|
936 | if (src_col->se_private_data().exists(s)) { |
| 9064 |
2/4✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
|
432 | src_col->se_private_data().get(s, &value); |
| 9065 |
2/4✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
|
432 | dest_col->se_private_data().set(s, value); |
| 9066 | } | ||
| 9067 | 1080 | }; | |
| 9068 | |||
| 9069 | 144 | uint32_t v_added = UINT32_UNDEFINED; | |
| 9070 | 144 | const char *s = dd_column_key_strings[DD_INSTANT_VERSION_ADDED]; | |
| 9071 |
1/2✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
|
144 | fn(s, v_added); |
| 9072 | |||
| 9073 | 144 | uint32_t v_dropped = UINT32_UNDEFINED; | |
| 9074 | 144 | s = dd_column_key_strings[DD_INSTANT_VERSION_DROPPED]; | |
| 9075 |
1/2✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
|
144 | fn(s, v_dropped); |
| 9076 | |||
| 9077 | 144 | uint32_t phy_pos = UINT32_UNDEFINED; | |
| 9078 | 144 | s = dd_column_key_strings[DD_INSTANT_PHYSICAL_POS]; | |
| 9079 |
4/8✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 144 times.
|
144 | ut_ad(src_col->se_private_data().exists(s)); |
| 9080 |
1/2✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
|
144 | fn(s, phy_pos); |
| 9081 | |||
| 9082 | 144 | s = dd_column_key_strings[DD_INSTANT_COLUMN_DEFAULT_NULL]; | |
| 9083 |
5/8✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 138 times.
|
144 | if (src_col->se_private_data().exists(s)) { |
| 9084 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | ut_ad(v_added > 0); |
| 9085 | 6 | bool value = false; | |
| 9086 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | fn(s, value); |
| 9087 | } else { | ||
| 9088 | 138 | s = dd_column_key_strings[DD_INSTANT_COLUMN_DEFAULT]; | |
| 9089 |
5/8✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 108 times.
|
138 | if (src_col->se_private_data().exists(s)) { |
| 9090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | ut_ad(v_added > 0); |
| 9091 | 30 | dd::String_type value; | |
| 9092 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | fn(s, value); |
| 9093 | 30 | } else { | |
| 9094 | /* This columns is not INSTANT ADD or this column is already dropped. */ | ||
| 9095 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
|
108 | ut_ad(v_added == UINT32_UNDEFINED || v_dropped > 0); |
| 9096 | } | ||
| 9097 | } | ||
| 9098 | } | ||
| 9099 | 24 | } | |
| 9100 | |||
| 9101 | /** Class which handles the partition of states | ||
| 9102 | PART_TO_BE_DROPPED, PART_TO_BE_REORGED and PART_REORGED_DROPPED. | ||
| 9103 | See comments for alter_part_factory::create_for_reorg | ||
| 9104 | and alter_part_factory::create_for_non_reorg. */ | ||
| 9105 | class alter_part_drop : public alter_part { | ||
| 9106 | public: | ||
| 9107 | /** Constructor | ||
| 9108 | @param[in] part_id Partition id in the table. This could | ||
| 9109 | be partition id for either old table | ||
| 9110 | or new table, callers should remember | ||
| 9111 | which one is applicable | ||
| 9112 | @param[in] state Partition state of the partition on | ||
| 9113 | which this class will do operations. | ||
| 9114 | If this is for one partition in new | ||
| 9115 | table, the partition state is the same | ||
| 9116 | for both the new partition and the | ||
| 9117 | corresponding old partition | ||
| 9118 | @param[in] table_name Partitioned table name, in the form | ||
| 9119 | of db/table, which already considers | ||
| 9120 | the charset | ||
| 9121 | @param[in,out] trx InnoDB transaction | ||
| 9122 | @param[in,out] old InnoDB table object for old partition, | ||
| 9123 | default is nullptr, which means there | ||
| 9124 | is no corresponding object | ||
| 9125 | @param[in] conflict True if there is already a partition | ||
| 9126 | table with the same name */ | ||
| 9127 | 1384 | alter_part_drop(uint part_id, partition_state state, const char *table_name, | |
| 9128 | trx_t *trx, dict_table_t **old, bool conflict) | ||
| 9129 | 1384 | : alter_part(trx, part_id, state, table_name, old), | |
| 9130 | 1384 | m_conflict(conflict) {} | |
| 9131 | |||
| 9132 | /** Destructor */ | ||
| 9133 | 2524 | ~alter_part_drop() override = default; | |
| 9134 | |||
| 9135 | /** Try to commit | ||
| 9136 | @param[in] table Table definition before the ALTER | ||
| 9137 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9138 | @param[in] old_part the stored old partition or nullptr | ||
| 9139 | if no corresponding one exists | ||
| 9140 | @param[in,out] new_part the stored new partition or nullptr | ||
| 9141 | if no corresponding one exists | ||
| 9142 | @return 0 or error number */ | ||
| 9143 | 1306 | int try_commit(const TABLE *table [[maybe_unused]], | |
| 9144 | TABLE *altered_table [[maybe_unused]], | ||
| 9145 | const dd::Partition *old_part, | ||
| 9146 | dd::Partition *new_part) override { | ||
| 9147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1306 times.
|
1306 | ut_ad(new_part == nullptr); |
| 9148 | |||
| 9149 |
1/2✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
|
1306 | dict_sys_mutex_enter(); |
| 9150 |
1/2✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
|
1306 | dict_table_ddl_acquire(*m_old); |
| 9151 |
1/2✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
|
1306 | dict_sys_mutex_exit(); |
| 9152 |
1/2✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
|
1306 | dd_table_close(*m_old, nullptr, nullptr, false); |
| 9153 | |||
| 9154 | int error; | ||
| 9155 | char part_name[FN_REFLEN]; | ||
| 9156 | 1306 | THD *thd = m_trx->mysql_thd; | |
| 9157 | |||
| 9158 |
2/4✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1306 times.
|
1306 | if (!build_partition_name(old_part, false, part_name)) { |
| 9159 | ✗ | return (HA_ERR_TOO_LONG_PATH); /* purecov: inspected */ | |
| 9160 | } | ||
| 9161 | |||
| 9162 |
2/2✓ Branch 0 taken 1236 times.
✓ Branch 1 taken 70 times.
|
1306 | if (!m_conflict) { |
| 9163 |
1/2✓ Branch 0 taken 1226 times.
✗ Branch 1 not taken.
|
1236 | error = innobase_basic_ddl::delete_impl<dd::Partition>(thd, part_name, |
| 9164 | old_part, nullptr); | ||
| 9165 |
2/6✓ Branch 0 taken 1226 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1226 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1226 | DBUG_EXECUTE_IF("drop_part_fail", error = DB_ERROR; |
| 9166 | my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));); | ||
| 9167 | } else { | ||
| 9168 | /* Have to rename it to a temporary name to prevent | ||
| 9169 | name conflict, because later deleting table doesn't | ||
| 9170 | remove the data file at once. Also notice that don't | ||
| 9171 | use the #tmp name, because it could be already used | ||
| 9172 | by the corresponding new partition. */ | ||
| 9173 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | mem_heap_t *heap = mem_heap_create(FN_REFLEN, UT_LOCATION_HERE); |
| 9174 | |||
| 9175 | 140 | char *temp_name = dict_mem_create_temporary_tablename( | |
| 9176 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | heap, (*m_old)->name.m_name, (*m_old)->id); |
| 9177 | |||
| 9178 | 70 | std::string db_str; | |
| 9179 | 70 | std::string tbl_str; | |
| 9180 |
2/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
|
70 | dict_name::get_table(temp_name, db_str, tbl_str); |
| 9181 | |||
| 9182 | /* Acquire mdl lock on the temporary table name. */ | ||
| 9183 | 70 | MDL_ticket *mdl_ticket = nullptr; | |
| 9184 |
2/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
|
70 | if (dd::acquire_exclusive_table_mdl(thd, db_str.c_str(), tbl_str.c_str(), |
| 9185 | false, &mdl_ticket)) { | ||
| 9186 | ✗ | mem_heap_free(heap); | |
| 9187 | ✗ | return (HA_ERR_GENERIC); | |
| 9188 | } | ||
| 9189 | |||
| 9190 |
1/2✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
|
70 | error = innobase_basic_ddl::rename_impl<dd::Partition>( |
| 9191 | thd, part_name, temp_name, old_part, old_part, nullptr); | ||
| 9192 |
1/2✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
|
67 | if (error == 0) { |
| 9193 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
67 | error = innobase_basic_ddl::delete_impl<dd::Partition>( |
| 9194 | thd, temp_name, old_part, nullptr); | ||
| 9195 | } | ||
| 9196 | |||
| 9197 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | mem_heap_free(heap); |
| 9198 |
2/4✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
|
65 | } |
| 9199 | |||
| 9200 |
1/2✓ Branch 0 taken 1291 times.
✗ Branch 1 not taken.
|
1291 | free_old_part(error != 0, part_name); |
| 9201 | |||
| 9202 | 1291 | return (error); | |
| 9203 | } | ||
| 9204 | |||
| 9205 | private: | ||
| 9206 | /** True if there is already a partition table with the same name */ | ||
| 9207 | const bool m_conflict; | ||
| 9208 | }; | ||
| 9209 | |||
| 9210 | /** Class which handles the partition of the state PART_CHANGED. | ||
| 9211 | See comments for alter_part_factory::create_for_reorg | ||
| 9212 | and alter_part_factory::create_for_non_reorg. */ | ||
| 9213 | class alter_part_change : public alter_part { | ||
| 9214 | public: | ||
| 9215 | /** Constructor | ||
| 9216 | @param[in] part_id Partition id in the table. This could | ||
| 9217 | be partition id for either old table | ||
| 9218 | or new table, callers should remember | ||
| 9219 | which one is applicable | ||
| 9220 | @param[in] state Partition state of the partition on | ||
| 9221 | which this class will do operations. | ||
| 9222 | If this is for one partition in new | ||
| 9223 | table, the partition state is the same | ||
| 9224 | for both the new partition and the | ||
| 9225 | corresponding old partition | ||
| 9226 | @param[in] table_name Partitioned table name, in the form | ||
| 9227 | of db/table, which already considers | ||
| 9228 | the chraset | ||
| 9229 | @param[in] tablespace Tablespace specified explicitly | ||
| 9230 | @param[in,out] trx InnoDB transaction | ||
| 9231 | @param[in,out] old InnoDB table object for old partition, | ||
| 9232 | default is nullptr, which means there | ||
| 9233 | is no corresponding object | ||
| 9234 | @param[in] ha_alter_info ALTER information | ||
| 9235 | @param[in] file_per_table Current value of innodb_file_per_table | ||
| 9236 | @param[in] autoinc Next AUTOINC value to use */ | ||
| 9237 | 894 | alter_part_change(uint part_id, partition_state state, const char *table_name, | |
| 9238 | const char *tablespace, trx_t *trx, dict_table_t **old, | ||
| 9239 | const Alter_inplace_info *ha_alter_info, | ||
| 9240 | bool file_per_table, uint64_t autoinc) | ||
| 9241 | 894 | : alter_part(trx, part_id, state, table_name, old), | |
| 9242 | 894 | m_ha_alter_info(ha_alter_info), | |
| 9243 | 894 | m_file_per_table(file_per_table), | |
| 9244 | 894 | m_autoinc(autoinc) { | |
| 9245 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 894 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
894 | if (tablespace == nullptr || tablespace[0] == '\0') { |
| 9246 | 894 | m_tablespace[0] = '\0'; | |
| 9247 | } else { | ||
| 9248 | ✗ | strcpy(m_tablespace, tablespace); | |
| 9249 | } | ||
| 9250 | 894 | } | |
| 9251 | |||
| 9252 | /** Destructor */ | ||
| 9253 | 1428 | ~alter_part_change() override = default; | |
| 9254 | |||
| 9255 | /** Prepare | ||
| 9256 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9257 | @param[in] old_part the stored old partition or nullptr | ||
| 9258 | if no corresponding one exists | ||
| 9259 | @param[in,out] new_part the stored new partition or nullptr | ||
| 9260 | if no corresponding one exists | ||
| 9261 | @return 0 or error number */ | ||
| 9262 | int prepare(TABLE *altered_table, const dd::Partition *old_part, | ||
| 9263 | dd::Partition *new_part) override; | ||
| 9264 | |||
| 9265 | /** Try to commit | ||
| 9266 | @param[in] table Table definition before the ALTER | ||
| 9267 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9268 | @param[in] old_part the stored old partition or nullptr | ||
| 9269 | if no corresponding one exists | ||
| 9270 | @param[in,out] new_part the stored new partition or nullptr | ||
| 9271 | if no corresponding one exists | ||
| 9272 | @return 0 or error number */ | ||
| 9273 | int try_commit(const TABLE *table, TABLE *altered_table, | ||
| 9274 | const dd::Partition *old_part, | ||
| 9275 | dd::Partition *new_part) override; | ||
| 9276 | |||
| 9277 | /** Rollback */ | ||
| 9278 | 43 | void rollback() override { | |
| 9279 | /* Release the new table so that in post DDL, this table can be | ||
| 9280 | rolled back. */ | ||
| 9281 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1 times.
|
43 | if (m_new != nullptr) { |
| 9282 | 42 | dd_table_close(m_new, m_trx->mysql_thd, nullptr, false); | |
| 9283 | 42 | m_new = nullptr; | |
| 9284 | } | ||
| 9285 | 43 | } | |
| 9286 | |||
| 9287 | private: | ||
| 9288 | /** ALTER information */ | ||
| 9289 | const Alter_inplace_info *m_ha_alter_info; | ||
| 9290 | |||
| 9291 | /** Current value of innodb_file_per_table */ | ||
| 9292 | const bool m_file_per_table; | ||
| 9293 | |||
| 9294 | /** Next AUTOINC value to use */ | ||
| 9295 | const uint64_t m_autoinc; | ||
| 9296 | |||
| 9297 | /** Tablespace of this partition */ | ||
| 9298 | char m_tablespace[FN_REFLEN + 1]; | ||
| 9299 | }; | ||
| 9300 | |||
| 9301 | /** Prepare | ||
| 9302 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9303 | @param[in] old_part the stored old partition or nullptr | ||
| 9304 | if no corresponding one exists | ||
| 9305 | @param[in,out] new_part the stored new partition or nullptr | ||
| 9306 | if no corresponding one exists | ||
| 9307 | @return 0 or error number */ | ||
| 9308 | 876 | int alter_part_change::prepare(TABLE *altered_table, | |
| 9309 | const dd::Partition *old_part, | ||
| 9310 | dd::Partition *new_part) { | ||
| 9311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 876 times.
|
876 | ut_ad(old_part != nullptr); |
| 9312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 876 times.
|
876 | ut_ad(new_part != nullptr); |
| 9313 | |||
| 9314 | /* In some scenario, it could be unnecessary to create partition | ||
| 9315 | with temporary name, for example, old one is in innodb_system while | ||
| 9316 | new one is innodb_file_per_table. However, this would result in | ||
| 9317 | same table name for two tables, which is confusing. So the temporary | ||
| 9318 | name is used always and final rename is necessary too */ | ||
| 9319 | char part_name[FN_REFLEN]; | ||
| 9320 | |||
| 9321 |
2/4✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 876 times.
|
876 | if (!build_partition_name(new_part, true, part_name)) { |
| 9322 | ✗ | return (HA_ERR_TOO_LONG_PATH); /* purecov: inspected */ | |
| 9323 | } | ||
| 9324 | |||
| 9325 | /* Copy the autoextend_size attribute for the partition being | ||
| 9326 | created. */ | ||
| 9327 |
1/2✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
|
876 | const dd::Table &part_table = old_part->table(); |
| 9328 | |||
| 9329 | 876 | ulonglong autoextend_size{}; | |
| 9330 | |||
| 9331 |
2/4✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 876 times.
✗ Branch 3 not taken.
|
876 | dd::get_implicit_tablespace_options(current_thd, &part_table, |
| 9332 | &autoextend_size); | ||
| 9333 | |||
| 9334 | int error = | ||
| 9335 |
3/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 849 times.
✓ Branch 2 taken 840 times.
✗ Branch 3 not taken.
|
876 | create(dd_table_has_instant_cols(part_table) ? &part_table : nullptr, |
| 9336 | 876 | part_name, new_part, altered_table, m_tablespace, m_file_per_table, | |
| 9337 |
1/2✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
|
876 | m_autoinc, autoextend_size); |
| 9338 | |||
| 9339 |
2/2✓ Branch 0 taken 839 times.
✓ Branch 1 taken 1 times.
|
840 | if (error == 0) { |
| 9340 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | dict_sys_mutex_enter(); |
| 9341 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | m_new = dict_table_check_if_in_cache_low(part_name); |
| 9342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 839 times.
|
839 | ut_ad(m_new != nullptr); |
| 9343 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | m_new->acquire(); |
| 9344 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | dict_table_ddl_release(m_new); |
| 9345 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | dict_sys_mutex_exit(); |
| 9346 | |||
| 9347 | 839 | return (m_new == nullptr); | |
| 9348 | } | ||
| 9349 | |||
| 9350 | 1 | return (error); | |
| 9351 | } | ||
| 9352 | |||
| 9353 | /** Try to commit | ||
| 9354 | @param[in] table Table definition before the ALTER | ||
| 9355 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9356 | @param[in] old_part the stored old partition or nullptr | ||
| 9357 | if no corresponding one exists | ||
| 9358 | @param[in,out] new_part the stored new partition or nullptr | ||
| 9359 | if no corresponding one exists | ||
| 9360 | @return 0 or error number */ | ||
| 9361 | 719 | int alter_part_change::try_commit(const TABLE *table [[maybe_unused]], | |
| 9362 | TABLE *altered_table [[maybe_unused]], | ||
| 9363 | const dd::Partition *old_part, | ||
| 9364 | dd::Partition *new_part) { | ||
| 9365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 719 times.
|
719 | ut_ad(old_part != nullptr); |
| 9366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 719 times.
|
719 | ut_ad(new_part != nullptr); |
| 9367 |
3/6✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 719 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 719 times.
|
719 | ut_ad(old_part->name() == new_part->name()); |
| 9368 | |||
| 9369 | 719 | THD *thd = m_trx->mysql_thd; | |
| 9370 | |||
| 9371 | 1438 | char *temp_old_name = dict_mem_create_temporary_tablename( | |
| 9372 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | (*m_old)->heap, (*m_old)->name.m_name, (*m_old)->id); |
| 9373 | |||
| 9374 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | dict_sys_mutex_enter(); |
| 9375 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | dict_table_ddl_acquire(*m_old); |
| 9376 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | dict_sys_mutex_exit(); |
| 9377 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | dd_table_close(*m_old, nullptr, nullptr, false); |
| 9378 | |||
| 9379 | 719 | std::string db_str; | |
| 9380 | 719 | std::string tbl_str; | |
| 9381 |
2/4✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 719 times.
✗ Branch 3 not taken.
|
719 | dict_name::get_table(temp_old_name, db_str, tbl_str); |
| 9382 | |||
| 9383 | /* Acquire mdl lock on the temporary table name. */ | ||
| 9384 | 719 | MDL_ticket *mdl_ticket = nullptr; | |
| 9385 |
2/4✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 719 times.
|
719 | if (dd::acquire_exclusive_table_mdl(thd, db_str.c_str(), tbl_str.c_str(), |
| 9386 | false, &mdl_ticket)) { | ||
| 9387 | ✗ | return (HA_ERR_GENERIC); | |
| 9388 | } | ||
| 9389 | |||
| 9390 | char old_name[FN_REFLEN]; | ||
| 9391 | char temp_name[FN_REFLEN]; | ||
| 9392 | |||
| 9393 |
3/6✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 719 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 719 times.
|
1438 | if (!build_partition_name(new_part, false, old_name) || |
| 9394 |
2/4✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 719 times.
|
719 | !build_partition_name(new_part, true, temp_name)) { |
| 9395 | ✗ | return (HA_ERR_TOO_LONG_PATH); /* purecov: inspected */ | |
| 9396 | } | ||
| 9397 | |||
| 9398 | int error; | ||
| 9399 | |||
| 9400 |
1/2✓ Branch 0 taken 707 times.
✗ Branch 1 not taken.
|
719 | error = innobase_basic_ddl::rename_impl<dd::Partition>( |
| 9401 | thd, old_name, temp_old_name, old_part, old_part, nullptr); | ||
| 9402 |
1/2✓ Branch 0 taken 707 times.
✗ Branch 1 not taken.
|
707 | if (error == 0) { |
| 9403 |
1/2✓ Branch 0 taken 695 times.
✗ Branch 1 not taken.
|
707 | error = innobase_basic_ddl::rename_impl<dd::Partition>( |
| 9404 | thd, temp_name, old_name, new_part, new_part, nullptr); | ||
| 9405 |
1/2✓ Branch 0 taken 695 times.
✗ Branch 1 not taken.
|
695 | if (error == 0) { |
| 9406 |
1/2✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
|
695 | error = innobase_basic_ddl::delete_impl<dd::Partition>(thd, temp_old_name, |
| 9407 | old_part, nullptr); | ||
| 9408 |
1/2✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
|
687 | free_old_part(error != 0, temp_old_name); |
| 9409 | } | ||
| 9410 | } | ||
| 9411 | |||
| 9412 |
1/2✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
|
687 | if (m_new != nullptr) { |
| 9413 |
1/2✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
|
687 | dd_table_close(m_new, thd, nullptr, false); |
| 9414 | 687 | m_new = nullptr; | |
| 9415 | } | ||
| 9416 | |||
| 9417 | 687 | return (error); | |
| 9418 | 687 | } | |
| 9419 | |||
| 9420 | /** Create alter_part_* object(s) for subpartitions of a partition, | ||
| 9421 | or the partition itself | ||
| 9422 | @param[in,out] array Where to store the new object(s) | ||
| 9423 | @param[in] part partition_element to handle | ||
| 9424 | @param[in,out] part_id Partition id for both partition and | ||
| 9425 | subpartition, which would be increased | ||
| 9426 | by number of object(s) created | ||
| 9427 | @param[in] old_part_id Start partition id of the table before | ||
| 9428 | ALTER TABLE | ||
| 9429 | @param[in] state Partition state | ||
| 9430 | @param[in] conflict Only valid when state is | ||
| 9431 | PART_TO_BE_ADDED. True if the new | ||
| 9432 | (sub)partition has the same name with | ||
| 9433 | an exist one and they are of | ||
| 9434 | innodb_file_per_table | ||
| 9435 | @retval false On success | ||
| 9436 | @retval true On failure */ | ||
| 9437 | 4333 | bool alter_part_factory::create_one(alter_part_array &array, | |
| 9438 | partition_element *part, uint &part_id, | ||
| 9439 | uint old_part_id, partition_state state, | ||
| 9440 | bool conflict) { | ||
| 9441 |
2/2✓ Branch 0 taken 616 times.
✓ Branch 1 taken 3717 times.
|
4333 | if (part->subpartitions.elements > 0) { |
| 9442 | partition_element *sub_elem; | ||
| 9443 |
1/2✓ Branch 0 taken 616 times.
✗ Branch 1 not taken.
|
616 | List_iterator_fast<partition_element> new_sub_it(part->subpartitions); |
| 9444 |
2/2✓ Branch 0 taken 1544 times.
✓ Branch 1 taken 616 times.
|
2160 | while ((sub_elem = new_sub_it++) != nullptr) { |
| 9445 | 3088 | const char *tablespace = partition_get_tablespace( | |
| 9446 |
1/2✓ Branch 0 taken 1544 times.
✗ Branch 1 not taken.
|
1544 | m_ha_alter_info->create_info->tablespace, part, sub_elem); |
| 9447 | alter_part *alter = | ||
| 9448 |
1/2✓ Branch 0 taken 1544 times.
✗ Branch 1 not taken.
|
1544 | create_one_low(part_id, old_part_id++, state, tablespace, conflict); |
| 9449 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1544 times.
|
1544 | if (alter == nullptr) { |
| 9450 | ✗ | return (true); | |
| 9451 | } | ||
| 9452 | |||
| 9453 | 1544 | ++part_id; | |
| 9454 |
1/2✓ Branch 0 taken 1544 times.
✗ Branch 1 not taken.
|
1544 | array.push_back(alter); |
| 9455 | } | ||
| 9456 | } else { | ||
| 9457 | 7434 | const char *tablespace = partition_get_tablespace( | |
| 9458 |
1/2✓ Branch 0 taken 3717 times.
✗ Branch 1 not taken.
|
3717 | m_ha_alter_info->create_info->tablespace, part, nullptr); |
| 9459 | alter_part *alter = | ||
| 9460 |
1/2✓ Branch 0 taken 3717 times.
✗ Branch 1 not taken.
|
3717 | create_one_low(part_id, old_part_id++, state, tablespace, conflict); |
| 9461 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3717 times.
|
3717 | if (alter == nullptr) { |
| 9462 | ✗ | return (true); | |
| 9463 | } | ||
| 9464 | |||
| 9465 | 3717 | ++part_id; | |
| 9466 |
1/2✓ Branch 0 taken 3717 times.
✗ Branch 1 not taken.
|
3717 | array.push_back(alter); |
| 9467 | } | ||
| 9468 | |||
| 9469 | 4333 | return (false); | |
| 9470 | } | ||
| 9471 | |||
| 9472 | /** Create the specified alter_part_* object | ||
| 9473 | @param[in] part_id Partition id for current partition | ||
| 9474 | |||
| 9475 | @param[in] old_part_id Start partition id of the table before | ||
| 9476 | ALTER TABLE | ||
| 9477 | @param[in] state Partition state | ||
| 9478 | @param[in] tablespace Tablespace specified explicitly | ||
| 9479 | @param[in] conflict Only valid when state is | ||
| 9480 | PART_TO_BE_ADDED. True if the new | ||
| 9481 | (sub)partition has the same name with | ||
| 9482 | an exist one and they are of | ||
| 9483 | innodb_file_per_table | ||
| 9484 | @return alter_part_* object or nullptr */ | ||
| 9485 | 5261 | alter_part *alter_part_factory::create_one_low(uint &part_id, uint old_part_id, | |
| 9486 | partition_state state, | ||
| 9487 | const char *tablespace, | ||
| 9488 | bool conflict) { | ||
| 9489 | 5261 | alter_part *alter_part = nullptr; | |
| 9490 | |||
| 9491 |
4/5✓ Branch 0 taken 2095 times.
✓ Branch 1 taken 888 times.
✓ Branch 2 taken 1384 times.
✓ Branch 3 taken 894 times.
✗ Branch 4 not taken.
|
5261 | switch (state) { |
| 9492 | 2095 | case PART_NORMAL: | |
| 9493 |
1/2✓ Branch 0 taken 2095 times.
✗ Branch 1 not taken.
|
2095 | alter_part = ut::new_withkey<alter_part_normal>( |
| 9494 | ut::make_psi_memory_key(mem_key_partitioning), part_id, state, | ||
| 9495 | 2095 | m_part_share->get_table_part_ref(old_part_id)); | |
| 9496 | 2095 | break; | |
| 9497 | 888 | case PART_TO_BE_ADDED: | |
| 9498 | 888 | alter_part = ut::new_withkey<alter_part_add>( | |
| 9499 | ut::make_psi_memory_key(mem_key_partitioning), part_id, state, | ||
| 9500 | 888 | m_part_share->get_table_share()->normalized_path.str, tablespace, | |
| 9501 | 888 | m_trx, m_ha_alter_info, m_file_per_table, | |
| 9502 | 888 | m_part_share->next_auto_inc_val, conflict); | |
| 9503 | 888 | break; | |
| 9504 | 1384 | case PART_TO_BE_DROPPED: | |
| 9505 | case PART_TO_BE_REORGED: | ||
| 9506 | case PART_REORGED_DROPPED: | ||
| 9507 |
1/2✓ Branch 0 taken 1384 times.
✗ Branch 1 not taken.
|
1384 | alter_part = ut::new_withkey<alter_part_drop>( |
| 9508 | ut::make_psi_memory_key(mem_key_partitioning), part_id, state, | ||
| 9509 | 1384 | m_part_share->get_table_share()->normalized_path.str, m_trx, | |
| 9510 | 1384 | m_part_share->get_table_part_ref(old_part_id), conflict); | |
| 9511 | 1384 | break; | |
| 9512 | 894 | case PART_CHANGED: | |
| 9513 |
1/2✓ Branch 0 taken 894 times.
✗ Branch 1 not taken.
|
894 | alter_part = ut::new_withkey<alter_part_change>( |
| 9514 | ut::make_psi_memory_key(mem_key_partitioning), part_id, state, | ||
| 9515 | 894 | m_part_share->get_table_share()->normalized_path.str, tablespace, | |
| 9516 | 894 | m_trx, m_part_share->get_table_part_ref(old_part_id), m_ha_alter_info, | |
| 9517 | 894 | m_file_per_table, m_part_share->next_auto_inc_val); | |
| 9518 | 894 | break; | |
| 9519 | ✗ | default: | |
| 9520 | ✗ | ut_d(ut_error); | |
| 9521 | } | ||
| 9522 | |||
| 9523 | 5261 | return (alter_part); | |
| 9524 | } | ||
| 9525 | |||
| 9526 | /** Create alter_part_add object(s) along with checking if the | ||
| 9527 | partition (and its subpartitions) conflicts with any of the original ones | ||
| 9528 | This is only for REORGANIZE PARTITION | ||
| 9529 | @param[in] new_part The new partition to check | ||
| 9530 | @param[in,out] new_part_id Partition id for both partition and | ||
| 9531 | subpartition, which would be increased | ||
| 9532 | by number of subpartitions per partition here | ||
| 9533 | @param[in,out] all_news To store the alter_part_add objects here | ||
| 9534 | @retval false On success | ||
| 9535 | @retval true On failure */ | ||
| 9536 | 330 | bool alter_part_factory::create_new_checking_conflict( | |
| 9537 | partition_element *new_part, uint &new_part_id, | ||
| 9538 | alter_part_array &all_news) { | ||
| 9539 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
|
330 | ut_ad((m_ha_alter_info->handler_flags & |
| 9540 | Alter_inplace_info::REORGANIZE_PARTITION) != 0); | ||
| 9541 | |||
| 9542 | 330 | partition_info *part_info = m_ha_alter_info->modified_part_info; | |
| 9543 | /* To compare with this partition list which contains all the | ||
| 9544 | to be reorganized partitions */ | ||
| 9545 |
1/2✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
|
330 | List_iterator_fast<partition_element> tmp_part_it(part_info->temp_partitions); |
| 9546 | partition_element *tmp_part_elem; | ||
| 9547 | |||
| 9548 |
2/2✓ Branch 0 taken 429 times.
✓ Branch 1 taken 246 times.
|
675 | while ((tmp_part_elem = tmp_part_it++) != nullptr) { |
| 9549 |
3/4✓ Branch 0 taken 429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 345 times.
✓ Branch 3 taken 84 times.
|
429 | if (!is_conflict(new_part, tmp_part_elem)) { |
| 9550 | 345 | continue; | |
| 9551 | } | ||
| 9552 | |||
| 9553 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 76 times.
|
84 | if (m_ha_alter_info->modified_part_info->is_sub_partitioned()) { |
| 9554 | List_iterator_fast<partition_element> tmp_sub_it( | ||
| 9555 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | tmp_part_elem->subpartitions); |
| 9556 | partition_element *tmp_sub_elem; | ||
| 9557 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | List_iterator_fast<partition_element> new_sub_it(new_part->subpartitions); |
| 9558 | partition_element *new_sub_elem; | ||
| 9559 | |||
| 9560 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
|
26 | while ((new_sub_elem = new_sub_it++) != nullptr) { |
| 9561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(new_sub_elem->partition_name != nullptr); |
| 9562 | 18 | tmp_sub_elem = tmp_sub_it++; | |
| 9563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(tmp_sub_elem != nullptr); |
| 9564 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(tmp_sub_elem->partition_name != nullptr); |
| 9565 | |||
| 9566 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | bool conflict = is_conflict(new_sub_elem, tmp_sub_elem); |
| 9567 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | if (create_one(all_news, new_sub_elem, new_part_id, 0, PART_TO_BE_ADDED, |
| 9568 | conflict)) { | ||
| 9569 | ✗ | return (true); | |
| 9570 | } | ||
| 9571 | } | ||
| 9572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | ut_ad((tmp_sub_elem = tmp_sub_it++) == nullptr); |
| 9573 | } else { | ||
| 9574 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76 times.
|
76 | if (create_one(all_news, new_part, new_part_id, 0, PART_TO_BE_ADDED, |
| 9575 | true)) { | ||
| 9576 | ✗ | return (true); | |
| 9577 | } | ||
| 9578 | } | ||
| 9579 | |||
| 9580 | /* Once matched, all are done */ | ||
| 9581 | 84 | return (false); | |
| 9582 | } | ||
| 9583 | |||
| 9584 | return ( | ||
| 9585 |
1/2✓ Branch 0 taken 246 times.
✗ Branch 1 not taken.
|
246 | create_one(all_news, new_part, new_part_id, 0, PART_TO_BE_ADDED, false)); |
| 9586 | } | ||
| 9587 | |||
| 9588 | /** Create alter_part_drop object(s) along with checking if the | ||
| 9589 | partition (and its subpartitions) conflicts with any of the to | ||
| 9590 | be created ones. | ||
| 9591 | This is only for REORGANIZE PARTITION | ||
| 9592 | @param[in] old_part The old partition to check | ||
| 9593 | @param[in,out] old_part_id Partition id for this partition or | ||
| 9594 | the first subpartition, which would | ||
| 9595 | be increased by number of subpartitions | ||
| 9596 | per partition here | ||
| 9597 | @param[in,out] to_drop To store the alter_part_drop objects | ||
| 9598 | @retval false On success | ||
| 9599 | @retval true On failure */ | ||
| 9600 | 359 | bool alter_part_factory::create_old_checking_conflict( | |
| 9601 | partition_element *old_part, uint &old_part_id, alter_part_array &to_drop) { | ||
| 9602 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | ut_ad((m_ha_alter_info->handler_flags & |
| 9603 | Alter_inplace_info::REORGANIZE_PARTITION) != 0); | ||
| 9604 | |||
| 9605 | 359 | partition_info *part_info = m_ha_alter_info->modified_part_info; | |
| 9606 | /* To compare with this partition list which contains all the | ||
| 9607 | new to be added partitions */ | ||
| 9608 |
1/2✓ Branch 0 taken 359 times.
✗ Branch 1 not taken.
|
359 | List_iterator_fast<partition_element> part_it(part_info->partitions); |
| 9609 | partition_element *part_elem; | ||
| 9610 | |||
| 9611 |
2/2✓ Branch 0 taken 836 times.
✓ Branch 1 taken 275 times.
|
1111 | while ((part_elem = part_it++) != nullptr) { |
| 9612 |
3/4✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 752 times.
✓ Branch 3 taken 84 times.
|
836 | if (!is_conflict(part_elem, old_part)) { |
| 9613 | 752 | continue; | |
| 9614 | } | ||
| 9615 | |||
| 9616 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 76 times.
|
84 | if (m_ha_alter_info->modified_part_info->is_sub_partitioned()) { |
| 9617 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | List_iterator_fast<partition_element> sub_it(part_elem->subpartitions); |
| 9618 | partition_element *sub_elem; | ||
| 9619 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | List_iterator_fast<partition_element> old_sub_it(old_part->subpartitions); |
| 9620 | partition_element *old_sub_elem; | ||
| 9621 | |||
| 9622 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
|
26 | while ((old_sub_elem = old_sub_it++) != nullptr) { |
| 9623 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(old_sub_elem->partition_name != nullptr); |
| 9624 | 18 | sub_elem = sub_it++; | |
| 9625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(sub_elem != nullptr); |
| 9626 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | ut_ad(sub_elem->partition_name != nullptr); |
| 9627 | |||
| 9628 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | bool conflict = is_conflict(sub_elem, old_sub_elem); |
| 9629 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | if (create_one(to_drop, old_sub_elem, old_part_id, old_part_id, |
| 9630 | PART_TO_BE_REORGED, conflict)) { | ||
| 9631 | ✗ | return (true); | |
| 9632 | } | ||
| 9633 | } | ||
| 9634 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | ut_ad((sub_elem = sub_it++) == nullptr); |
| 9635 | } else { | ||
| 9636 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76 times.
|
76 | if (create_one(to_drop, old_part, old_part_id, old_part_id, |
| 9637 | PART_TO_BE_REORGED, true)) { | ||
| 9638 | ✗ | return (true); | |
| 9639 | } | ||
| 9640 | } | ||
| 9641 | |||
| 9642 | /* Once matched, all are done */ | ||
| 9643 | 84 | return (false); | |
| 9644 | } | ||
| 9645 | |||
| 9646 |
1/2✓ Branch 0 taken 275 times.
✗ Branch 1 not taken.
|
275 | return (create_one(to_drop, old_part, old_part_id, old_part_id, |
| 9647 | 275 | PART_TO_BE_REORGED, false)); | |
| 9648 | } | ||
| 9649 | |||
| 9650 | /** Check if the two (sub)partitions conflict with each other, | ||
| 9651 | Which means they have same name. | ||
| 9652 | @param[in] new_part New partition to check | ||
| 9653 | @param[in] old_part Old partition to check | ||
| 9654 | @retval true Conflict | ||
| 9655 | @retval false Not conflict */ | ||
| 9656 | 1301 | bool alter_part_factory::is_conflict(const partition_element *new_part, | |
| 9657 | const partition_element *old_part) { | ||
| 9658 | 1301 | if (my_strcasecmp(system_charset_info, new_part->partition_name, | |
| 9659 |
2/2✓ Branch 0 taken 1109 times.
✓ Branch 1 taken 192 times.
|
1301 | old_part->partition_name) != 0) { |
| 9660 | 1109 | return (false); | |
| 9661 | } | ||
| 9662 | |||
| 9663 | /* To prevent the conflict(same) names in table cache, not to | ||
| 9664 | check the innodb_file_per_table */ | ||
| 9665 | 192 | return (true); | |
| 9666 | } | ||
| 9667 | |||
| 9668 | /** Suppose that there is a table with 4 range partitions: p0, p1, p2, p3, | ||
| 9669 | and the p2 and p3 are going to be reorganized into p21, p22, p31, p33. | ||
| 9670 | |||
| 9671 | In modified_part_info->temp_partitions list, there are only p2 and p3 | ||
| 9672 | with the state PART_TO_BE_REORGED, while in modified_part_info->partitions | ||
| 9673 | list, it contains | ||
| 9674 | {PART_NORMAL, PART_NORMAL, PART_TO_BE_ADDED, PART_TO_BE_ADDED, | ||
| 9675 | PART_TO_BE_ADDED, PART_TO_BE_ADDED}. | ||
| 9676 | |||
| 9677 | So finally, the to_drop array would contain | ||
| 9678 | {alter_part_drop, alter_part_drop}, which are for p2, p3; | ||
| 9679 | the all_news array would contains | ||
| 9680 | {alter_part_normal, alter_part_normal, alter_part_add, alter_part_add, | ||
| 9681 | alter_part_add, alter_part_add}. | ||
| 9682 | |||
| 9683 | Note that the scenario that reorganized and to be reorganized | ||
| 9684 | partition/subpartition have the same name, would be checked here too */ | ||
| 9685 | |||
| 9686 | /** Create the alter_part_* objects when it's an operation like | ||
| 9687 | REORGANIZE PARTITION | ||
| 9688 | @param[in,out] to_drop To store the alter_part_* objects | ||
| 9689 | for partitions to be dropped | ||
| 9690 | @param[in,out] all_news To store the alter_part_* objects | ||
| 9691 | for partitions in table after ALTER TABLE | ||
| 9692 | @return false On success | ||
| 9693 | @retval true On failure */ | ||
| 9694 | 224 | bool alter_part_factory::create_for_reorg(alter_part_array &to_drop, | |
| 9695 | alter_part_array &all_news) { | ||
| 9696 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad((m_ha_alter_info->handler_flags & |
| 9697 | Alter_inplace_info::REORGANIZE_PARTITION) != 0); | ||
| 9698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad(m_ha_alter_info->modified_part_info->num_subparts == |
| 9699 | m_old_part_info->num_subparts); | ||
| 9700 | |||
| 9701 | 224 | partition_info *part_info = m_ha_alter_info->modified_part_info; | |
| 9702 | /* This list contains only the to be reorganized partitions, | ||
| 9703 | the sequence is the same as the list of m_old_part_info, | ||
| 9704 | and they should be consecutive ones */ | ||
| 9705 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | List_iterator_fast<partition_element> tmp_part_it(part_info->temp_partitions); |
| 9706 | /* This list contains all the new partitions */ | ||
| 9707 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | List_iterator_fast<partition_element> part_it(part_info->partitions); |
| 9708 | /* This list contains all the old partitions */ | ||
| 9709 | List_iterator_fast<partition_element> old_part_it( | ||
| 9710 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | m_old_part_info->partitions); |
| 9711 | partition_element *part_elem; | ||
| 9712 | partition_element *tmp_part_elem; | ||
| 9713 | partition_element *old_part_elem; | ||
| 9714 | uint parts_per_part = | ||
| 9715 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 209 times.
|
224 | part_info->is_sub_partitioned() ? part_info->num_subparts : 1; |
| 9716 | |||
| 9717 | 224 | tmp_part_elem = tmp_part_it++; | |
| 9718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad(tmp_part_elem != nullptr); |
| 9719 | 224 | old_part_elem = old_part_it++; | |
| 9720 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad(old_part_elem != nullptr); |
| 9721 | |||
| 9722 | 224 | uint old_part_id = 0; | |
| 9723 | 224 | uint new_part_id = 0; | |
| 9724 | |||
| 9725 | /* There are 3 steps here: | ||
| 9726 | 1. Check if the old one is a to be reorganized one, if so, mark it | ||
| 9727 | and check next old one | ||
| 9728 | 2. If not, check if the new one is a to be added one, if so, mark it | ||
| 9729 | and check next new one | ||
| 9730 | 3. If not, the old one and the new one should point to the same | ||
| 9731 | partition */ | ||
| 9732 |
2/2✓ Branch 0 taken 562 times.
✓ Branch 1 taken 224 times.
|
786 | while ((part_elem = part_it++) != nullptr) { |
| 9733 |
4/4✓ Branch 0 taken 659 times.
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 519 times.
✓ Branch 3 taken 140 times.
|
921 | while (old_part_elem != nullptr && tmp_part_elem != nullptr && |
| 9734 |
2/2✓ Branch 0 taken 359 times.
✓ Branch 1 taken 160 times.
|
519 | strcmp(tmp_part_elem->partition_name, |
| 9735 | old_part_elem->partition_name) == 0) { | ||
| 9736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
|
359 | ut_ad(tmp_part_elem->part_state == PART_TO_BE_REORGED); |
| 9737 | |||
| 9738 |
2/4✓ Branch 0 taken 359 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 359 times.
|
359 | if (create_old_checking_conflict(old_part_elem, old_part_id, to_drop)) { |
| 9739 | ✗ | return (true); | |
| 9740 | } | ||
| 9741 | |||
| 9742 | 359 | old_part_elem = old_part_it++; | |
| 9743 | 359 | tmp_part_elem = tmp_part_it++; | |
| 9744 | } | ||
| 9745 | |||
| 9746 |
2/3✓ Branch 0 taken 330 times.
✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
|
562 | switch (part_elem->part_state) { |
| 9747 | 330 | case PART_TO_BE_ADDED: | |
| 9748 | |||
| 9749 |
2/4✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 330 times.
|
330 | if (create_new_checking_conflict(part_elem, new_part_id, all_news)) { |
| 9750 | ✗ | return (true); | |
| 9751 | } | ||
| 9752 | |||
| 9753 | 330 | break; | |
| 9754 | |||
| 9755 | 232 | case PART_NORMAL: | |
| 9756 | |||
| 9757 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
|
232 | ut_ad(strcmp(part_elem->partition_name, |
| 9758 | old_part_elem->partition_name) == 0); | ||
| 9759 | |||
| 9760 |
2/4✓ Branch 0 taken 232 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 232 times.
|
232 | if (create_one(all_news, part_elem, new_part_id, old_part_id, |
| 9761 | PART_NORMAL, false)) { | ||
| 9762 | ✗ | return (true); | |
| 9763 | } | ||
| 9764 | |||
| 9765 | 232 | old_part_elem = old_part_it++; | |
| 9766 | 232 | old_part_id += parts_per_part; | |
| 9767 | |||
| 9768 | 232 | break; | |
| 9769 | |||
| 9770 | ✗ | default: | |
| 9771 | ✗ | ut_d(ut_error); | |
| 9772 | } | ||
| 9773 | } | ||
| 9774 | |||
| 9775 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad(old_part_elem == nullptr); |
| 9776 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | ut_ad(tmp_part_elem == nullptr); |
| 9777 | |||
| 9778 | 224 | return (false); | |
| 9779 | } | ||
| 9780 | |||
| 9781 | /** Suppose that there is a table with 4 range partitions: p0, p1, p2, p3. | ||
| 9782 | |||
| 9783 | 1. ADD PARTITION p4 | ||
| 9784 | modified_part_info->partitions list contains | ||
| 9785 | {PART_NORMAL, PART_NORMAL, PART_NORMAL, PART_NORMAL, PART_TO_BE_ADDED}. | ||
| 9786 | |||
| 9787 | So finally, the to_drop array would contain | ||
| 9788 | {}, which is empty; | ||
| 9789 | the all_news array would contains | ||
| 9790 | {alter_part_normal, alter_part_normal, alter_part_normal, alter_part_normal, | ||
| 9791 | alter_part_add}. | ||
| 9792 | |||
| 9793 | 2. DROP PARTITION p2 | ||
| 9794 | modified_part_info->partitions list contain | ||
| 9795 | {PART_NORMAL, PART_NORMAL, PART_TO_BE_DROPPED, PART_NORMAL}. | ||
| 9796 | |||
| 9797 | So finally, the to_drop array would contain | ||
| 9798 | {alter_part_drop}, which is for p2, so part_id is 2; | ||
| 9799 | the all_news array would contains | ||
| 9800 | {alter_part_normal, alter_part_normal, alter_part_normal}. | ||
| 9801 | |||
| 9802 | |||
| 9803 | Suppose it's the same table with 4 partitions, but it's partitioned by HASH. | ||
| 9804 | |||
| 9805 | 3. ADD PARTITION 2 | ||
| 9806 | modified_part_info->partitions list contains | ||
| 9807 | {PART_CHANGED, PART_CHANGED, PART_CHANGED, PART_CHANGED, PART_TO_BE_ADDED, | ||
| 9808 | PART_TO_BE_ADDED}. | ||
| 9809 | |||
| 9810 | So finally, the to_drop array would contain | ||
| 9811 | {}, which is empty; | ||
| 9812 | the all_news array would contains | ||
| 9813 | {alter_part_change, alter_part_change, alter_part_change, alter_part_change, | ||
| 9814 | alter_part_add, alter_part_add}. | ||
| 9815 | |||
| 9816 | 4. COALESCE PARTITION 2 | ||
| 9817 | modified_part_info->partitions contains: | ||
| 9818 | {PART_CHANGED, PART_CHANGED, PART_REORGED_DROPPED, PART_REORGED_DROPPED}. | ||
| 9819 | |||
| 9820 | So finally, the to_drop array would contain | ||
| 9821 | {alter_part_drop, alter_part_drop}, which are for p2, p3, part_id are 2 and 3; | ||
| 9822 | the all_news array would contains | ||
| 9823 | {alter_part_change, alter_part_change}. | ||
| 9824 | |||
| 9825 | 5. REBUILD PARTITION p0, p2 | ||
| 9826 | modified_part_info->partitions contains: | ||
| 9827 | {PART_NORMAL, PART_CHANGED, PART_NORMAL, PART_CHANGED}. | ||
| 9828 | |||
| 9829 | So finally, the to_drop array would contain | ||
| 9830 | {}, which is empty; | ||
| 9831 | the all_news array would contains | ||
| 9832 | {alter_part_normal, alter_part_change, alter_part_normal, alter_part_change}. */ | ||
| 9833 | |||
| 9834 | /** Create the alter_part_* objects when it's NOT an operation like | ||
| 9835 | REORGANIZE PARTITION | ||
| 9836 | @param[in,out] to_drop To store the alter_part_* objects | ||
| 9837 | for partitions to be dropped | ||
| 9838 | @param[in,out] all_news To store the alter_part_* objects | ||
| 9839 | for partitions in table after ALTER TABLE | ||
| 9840 | @return false On success | ||
| 9841 | @retval true On Failure */ | ||
| 9842 | 719 | bool alter_part_factory::create_for_non_reorg(alter_part_array &to_drop, | |
| 9843 | alter_part_array &all_news) { | ||
| 9844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 719 times.
|
719 | ut_ad((m_ha_alter_info->handler_flags & |
| 9845 | Alter_inplace_info::REORGANIZE_PARTITION) == 0); | ||
| 9846 | |||
| 9847 | 719 | partition_info *part_info = m_ha_alter_info->modified_part_info; | |
| 9848 | uint parts_per_part = | ||
| 9849 |
2/2✓ Branch 0 taken 161 times.
✓ Branch 1 taken 558 times.
|
719 | part_info->is_sub_partitioned() ? part_info->num_subparts : 1; |
| 9850 |
1/2✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
|
719 | List_iterator_fast<partition_element> part_it(part_info->partitions); |
| 9851 | partition_element *part_elem; | ||
| 9852 | 719 | uint old_part_id = 0; | |
| 9853 | 719 | uint new_part_id = 0; | |
| 9854 | |||
| 9855 |
2/2✓ Branch 0 taken 3392 times.
✓ Branch 1 taken 719 times.
|
4111 | while ((part_elem = part_it++) != nullptr) { |
| 9856 | 3392 | partition_state state = part_elem->part_state; | |
| 9857 |
3/4✓ Branch 0 taken 2014 times.
✓ Branch 1 taken 513 times.
✓ Branch 2 taken 865 times.
✗ Branch 3 not taken.
|
3392 | switch (state) { |
| 9858 | 2014 | case PART_NORMAL: | |
| 9859 | case PART_CHANGED: | ||
| 9860 |
2/4✓ Branch 0 taken 2014 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2014 times.
|
2014 | if (create_one(all_news, part_elem, new_part_id, old_part_id, state, |
| 9861 | false)) { | ||
| 9862 | ✗ | return (true); | |
| 9863 | } | ||
| 9864 | |||
| 9865 | 2014 | old_part_id += parts_per_part; | |
| 9866 | 2014 | break; | |
| 9867 | 513 | case PART_TO_BE_ADDED: | |
| 9868 |
2/4✓ Branch 0 taken 513 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 513 times.
|
513 | if (create_one(all_news, part_elem, new_part_id, 0, state, false)) { |
| 9869 | ✗ | return (true); | |
| 9870 | } | ||
| 9871 | |||
| 9872 | 513 | break; | |
| 9873 | 865 | case PART_TO_BE_DROPPED: | |
| 9874 | case PART_REORGED_DROPPED: | ||
| 9875 |
2/4✓ Branch 0 taken 865 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 865 times.
|
865 | if (create_one(to_drop, part_elem, old_part_id, old_part_id, state, |
| 9876 | false)) { | ||
| 9877 | ✗ | return (true); | |
| 9878 | } | ||
| 9879 | |||
| 9880 | 865 | break; | |
| 9881 | ✗ | default: | |
| 9882 | ✗ | ut_d(ut_error); | |
| 9883 | } | ||
| 9884 | } | ||
| 9885 | |||
| 9886 | 719 | return (false); | |
| 9887 | } | ||
| 9888 | |||
| 9889 | #ifndef NDEBUG | ||
| 9890 | /** Check if the specified partition_state is of drop state | ||
| 9891 | @param[in] s The state to be checked | ||
| 9892 | @retval true if this is of a drop state | ||
| 9893 | @retval false if not */ | ||
| 9894 | 810 | inline static bool is_drop_state(partition_state s) { | |
| 9895 |
4/6✓ Branch 0 taken 120 times.
✓ Branch 1 taken 690 times.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
|
810 | return (s == PART_TO_BE_DROPPED || s == PART_REORGED_DROPPED || |
| 9896 | 810 | s == PART_TO_BE_REORGED); | |
| 9897 | } | ||
| 9898 | #endif | ||
| 9899 | |||
| 9900 | /** Check if the specified partition_state is of common state | ||
| 9901 | @param[in] s The state to be checked | ||
| 9902 | @retval true if this is of a common state | ||
| 9903 | @retval false if not */ | ||
| 9904 | 8868 | inline static bool is_common_state(partition_state s) { | |
| 9905 |
4/4✓ Branch 0 taken 4901 times.
✓ Branch 1 taken 3967 times.
✓ Branch 2 taken 1595 times.
✓ Branch 3 taken 3306 times.
|
8868 | return (s == PART_NORMAL || s == PART_CHANGED); |
| 9906 | } | ||
| 9907 | |||
| 9908 | /** Destructor */ | ||
| 9909 | 1636 | alter_parts::~alter_parts() { | |
| 9910 |
2/2✓ Branch 0 taken 3480 times.
✓ Branch 1 taken 818 times.
|
8596 | for (alter_part *alter_part : m_news) { |
| 9911 | 6960 | ut::delete_(alter_part); | |
| 9912 | } | ||
| 9913 | |||
| 9914 |
2/2✓ Branch 0 taken 1262 times.
✓ Branch 1 taken 818 times.
|
4160 | for (alter_part *alter_part : m_to_drop) { |
| 9915 | 2524 | ut::delete_(alter_part); | |
| 9916 | } | ||
| 9917 | } | ||
| 9918 | |||
| 9919 | /** Create the to be created partitions and update internal | ||
| 9920 | structures with concurrent writes blocked, while preparing | ||
| 9921 | ALTER TABLE. | ||
| 9922 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 9923 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 9924 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9925 | @return 0 or error number, my_error() should be called by callers */ | ||
| 9926 | 943 | int alter_parts::prepare(const dd::Table &old_dd_tab, dd::Table &new_dd_tab, | |
| 9927 | TABLE *altered_table) { | ||
| 9928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 943 times.
|
943 | if (m_factory.create(m_to_drop, m_news)) { |
| 9929 | ✗ | return (true); | |
| 9930 | } | ||
| 9931 | |||
| 9932 |
2/2✓ Branch 0 taken 239 times.
✓ Branch 1 taken 704 times.
|
943 | if (m_part_share->get_table_share()->found_next_number_field) { |
| 9933 | 239 | dd_set_autoinc(new_dd_tab.se_private_data(), | |
| 9934 | 239 | m_ha_alter_info->create_info->auto_increment_value); | |
| 9935 | } | ||
| 9936 | |||
| 9937 | int error; | ||
| 9938 | 943 | error = prepare_or_commit_for_old(old_dd_tab, altered_table, true); | |
| 9939 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 943 times.
|
943 | if (error != 0) { |
| 9940 | ✗ | return (error); | |
| 9941 | } | ||
| 9942 | |||
| 9943 | error = | ||
| 9944 | 943 | prepare_or_commit_for_new(old_dd_tab, new_dd_tab, altered_table, true); | |
| 9945 | |||
| 9946 | /* We don't have to prepare for the partitions that will be dropped. */ | ||
| 9947 | |||
| 9948 | 868 | return (error); | |
| 9949 | } | ||
| 9950 | |||
| 9951 | /** Notify the storage engine that the changes made during | ||
| 9952 | prepare_inplace_alter_table() and inplace_alter_table() | ||
| 9953 | will be rolled back for all the partitions. */ | ||
| 9954 | 42 | void alter_parts::rollback() { | |
| 9955 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 42 times.
|
57 | for (alter_part *alter_part : m_to_drop) { |
| 9956 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | alter_part->rollback(); |
| 9957 | } | ||
| 9958 | |||
| 9959 |
2/2✓ Branch 0 taken 233 times.
✓ Branch 1 taken 42 times.
|
275 | for (alter_part *alter_part : m_news) { |
| 9960 |
1/2✓ Branch 0 taken 233 times.
✗ Branch 1 not taken.
|
233 | alter_part->rollback(); |
| 9961 | } | ||
| 9962 | 42 | } | |
| 9963 | |||
| 9964 | /** Try to commit the changes made during prepare_inplace_alter_table() | ||
| 9965 | inside the storage engine. This is protected by MDL_EXCLUSIVE. | ||
| 9966 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 9967 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 9968 | @param[in] table Table definition before the ALTER | ||
| 9969 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9970 | @return 0 or error number, my_error() should be called by callers */ | ||
| 9971 | 826 | int alter_parts::try_commit(const dd::Table &old_dd_tab, dd::Table &new_dd_tab, | |
| 9972 | const TABLE *table [[maybe_unused]], | ||
| 9973 | TABLE *altered_table) { | ||
| 9974 | int error; | ||
| 9975 | /* Commit for the old ones first, to clear data files for new ones */ | ||
| 9976 | 826 | error = prepare_or_commit_for_old(old_dd_tab, altered_table, false); | |
| 9977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 811 times.
|
811 | if (error != 0) { |
| 9978 | ✗ | return (error); | |
| 9979 | } | ||
| 9980 | |||
| 9981 | error = | ||
| 9982 | 811 | prepare_or_commit_for_new(old_dd_tab, new_dd_tab, altered_table, false); | |
| 9983 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 776 times.
|
776 | if (error != 0) { |
| 9984 | ✗ | return (error); | |
| 9985 | } | ||
| 9986 | |||
| 9987 | 776 | return (0); | |
| 9988 | } | ||
| 9989 | |||
| 9990 | /** Prepare for all the partitions in table after ALTER TABLE | ||
| 9991 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 9992 | @param[in,out] new_dd_tab dd::Table after ALTER TABLE | ||
| 9993 | @param[in,out] altered_table Table definition after the ALTER | ||
| 9994 | @param[in] prepare true if it's in prepare phase, | ||
| 9995 | false if it's in commit phase | ||
| 9996 | @return 0 or error number */ | ||
| 9997 | 1754 | int alter_parts::prepare_or_commit_for_new(const dd::Table &old_dd_tab, | |
| 9998 | dd::Table &new_dd_tab, | ||
| 9999 | TABLE *altered_table, bool prepare) { | ||
| 10000 |
1/2✓ Branch 0 taken 1754 times.
✗ Branch 1 not taken.
|
1754 | auto oldp = old_dd_tab.leaf_partitions().begin(); |
| 10001 | 1754 | uint new_part_id = 0; | |
| 10002 | 1754 | uint old_part_id = 0; | |
| 10003 | 1754 | uint drop_seq = 0; | |
| 10004 | 1754 | const dd::Partition *old_part = nullptr; | |
| 10005 | 1754 | int error = 0; | |
| 10006 | |||
| 10007 |
3/4✓ Branch 0 taken 1754 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7109 times.
✓ Branch 3 taken 1631 times.
|
8740 | for (auto new_part : *new_dd_tab.leaf_partitions()) { |
| 10008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7109 times.
|
7109 | ut_ad(new_part_id < m_news.size()); |
| 10009 | |||
| 10010 | /* To add a new partition, there is no corresponding old one, | ||
| 10011 | otherwise, find the old one */ | ||
| 10012 |
1/2✓ Branch 0 taken 7109 times.
✗ Branch 1 not taken.
|
7109 | partition_state s = m_news[new_part_id]->state(); |
| 10013 |
2/2✓ Branch 0 taken 5562 times.
✓ Branch 1 taken 1547 times.
|
7109 | if (is_common_state(s)) { |
| 10014 | 5562 | bool found = false; | |
| 10015 |
7/8✓ Branch 0 taken 11934 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10931 times.
✓ Branch 3 taken 1003 times.
✓ Branch 4 taken 6372 times.
✓ Branch 5 taken 4559 times.
✓ Branch 6 taken 6372 times.
✓ Branch 7 taken 5562 times.
|
11934 | for (; oldp != old_dd_tab.leaf_partitions().end() && !found; ++oldp) { |
| 10016 | 6372 | old_part = *oldp; | |
| 10017 | |||
| 10018 | 6372 | ++old_part_id; | |
| 10019 |
4/4✓ Branch 0 taken 2128 times.
✓ Branch 1 taken 4244 times.
✓ Branch 2 taken 810 times.
✓ Branch 3 taken 5562 times.
|
8500 | if (drop_seq < m_to_drop.size() && |
| 10020 |
3/4✓ Branch 0 taken 2128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 810 times.
✓ Branch 3 taken 1318 times.
|
2128 | (old_part_id - 1 == m_to_drop[drop_seq]->part_id())) { |
| 10021 |
2/4✓ Branch 0 taken 810 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 810 times.
|
810 | ut_ad(is_drop_state(m_to_drop[drop_seq]->state())); |
| 10022 | 810 | ++drop_seq; | |
| 10023 | 810 | continue; | |
| 10024 | } | ||
| 10025 | |||
| 10026 | 5562 | found = true; | |
| 10027 | } | ||
| 10028 | |||
| 10029 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5562 times.
|
5562 | ut_ad(found); |
| 10030 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5562 times.
|
5562 | ut_ad(drop_seq <= m_to_drop.size()); |
| 10031 |
3/6✓ Branch 0 taken 5562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5562 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5562 times.
|
5562 | ut_ad(new_part->name() == old_part->name()); |
| 10032 |
3/6✓ Branch 0 taken 5562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5562 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5562 times.
|
5562 | ut_ad((new_part->parent() == nullptr) == (old_part->parent() == nullptr)); |
| 10033 |
9/16✓ Branch 0 taken 5562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2294 times.
✓ Branch 3 taken 3268 times.
✓ Branch 4 taken 2294 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2294 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2294 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2294 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2294 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 5562 times.
|
5562 | ut_ad(new_part->parent() == nullptr || |
| 10034 | new_part->parent()->name() == old_part->parent()->name()); | ||
| 10035 | } else { | ||
| 10036 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1547 times.
|
1547 | ut_ad(s == PART_TO_BE_ADDED); |
| 10037 | /* Let's still set one to get the old table name */ | ||
| 10038 |
1/2✓ Branch 0 taken 1547 times.
✗ Branch 1 not taken.
|
1547 | old_part = *(old_dd_tab.leaf_partitions().begin()); |
| 10039 | } | ||
| 10040 | |||
| 10041 | 7109 | alter_part *alter_part = m_news[new_part_id]; | |
| 10042 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7109 times.
|
7109 | ut_ad(alter_part != nullptr); |
| 10043 | |||
| 10044 |
2/2✓ Branch 0 taken 3805 times.
✓ Branch 1 taken 3304 times.
|
7109 | if (prepare) { |
| 10045 |
1/2✓ Branch 0 taken 3730 times.
✗ Branch 1 not taken.
|
3805 | error = alter_part->prepare(altered_table, old_part, new_part); |
| 10046 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3717 times.
|
3730 | if (error != 0) { |
| 10047 | 13 | return (error); | |
| 10048 | } | ||
| 10049 | |||
| 10050 |
6/6✓ Branch 0 taken 2162 times.
✓ Branch 1 taken 1555 times.
✓ Branch 2 taken 1503 times.
✓ Branch 3 taken 659 times.
✓ Branch 4 taken 1503 times.
✓ Branch 5 taken 2214 times.
|
3717 | if (m_new_partitions != nullptr && alter_part->new_table() != nullptr) { |
| 10051 |
1/2✓ Branch 0 taken 1503 times.
✗ Branch 1 not taken.
|
1503 | m_new_partitions->set_part(new_part_id, alter_part->new_table()); |
| 10052 | } | ||
| 10053 | } else { | ||
| 10054 | error = | ||
| 10055 |
1/2✓ Branch 0 taken 3269 times.
✗ Branch 1 not taken.
|
3304 | alter_part->try_commit(nullptr, altered_table, old_part, new_part); |
| 10056 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3269 times.
|
3269 | if (error != 0) { |
| 10057 | ✗ | return (error); | |
| 10058 | } | ||
| 10059 | } | ||
| 10060 | |||
| 10061 | 6986 | ++new_part_id; | |
| 10062 | } | ||
| 10063 | |||
| 10064 | #ifdef UNIV_DEBUG | ||
| 10065 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1631 times.
|
1631 | ut_ad(drop_seq <= m_to_drop.size()); |
| 10066 |
2/2✓ Branch 0 taken 1759 times.
✓ Branch 1 taken 1631 times.
|
3390 | for (uint i = drop_seq; i < m_to_drop.size(); ++i) { |
| 10067 |
2/4✓ Branch 0 taken 1759 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1759 times.
|
1759 | ut_ad(!is_common_state(m_to_drop[i]->state())); |
| 10068 | } | ||
| 10069 | #endif /* UNIV_DEBUG */ | ||
| 10070 | |||
| 10071 | 1631 | return (error); | |
| 10072 | } | ||
| 10073 | |||
| 10074 | /** Prepare or commit for all the partitions in table before ALTER TABLE | ||
| 10075 | @param[in] old_dd_tab dd::Table before ALTER TABLE | ||
| 10076 | @param[in,out] altered_table Table definition after the ALTER | ||
| 10077 | @param[in] prepare true if it's in prepare phase, | ||
| 10078 | false if it's in commit phase | ||
| 10079 | @return 0 or error number */ | ||
| 10080 | 1769 | int alter_parts::prepare_or_commit_for_old(const dd::Table &old_dd_tab, | |
| 10081 | TABLE *altered_table, bool prepare) { | ||
| 10082 | 1769 | uint old_part_id = 0; | |
| 10083 |
1/2✓ Branch 0 taken 1769 times.
✗ Branch 1 not taken.
|
1769 | auto dd_part = old_dd_tab.leaf_partitions().begin(); |
| 10084 | 1769 | int error = 0; | |
| 10085 | |||
| 10086 |
2/2✓ Branch 0 taken 2690 times.
✓ Branch 1 taken 1754 times.
|
4444 | for (alter_part *alter_part : m_to_drop) { |
| 10087 | 2690 | const dd::Partition *old_part = nullptr; | |
| 10088 | |||
| 10089 |
2/4✓ Branch 0 taken 4053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4053 times.
✗ Branch 3 not taken.
|
4053 | for (; dd_part != old_dd_tab.leaf_partitions().end(); ++dd_part) { |
| 10090 |
3/4✓ Branch 0 taken 4053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1363 times.
✓ Branch 3 taken 2690 times.
|
4053 | if (old_part_id++ < alter_part->part_id()) { |
| 10091 | 1363 | continue; | |
| 10092 | } | ||
| 10093 | |||
| 10094 | 2690 | old_part = *dd_part; | |
| 10095 | 2690 | ++dd_part; | |
| 10096 | 2690 | break; | |
| 10097 | } | ||
| 10098 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2690 times.
|
2690 | ut_ad(old_part != nullptr); |
| 10099 | |||
| 10100 |
2/2✓ Branch 0 taken 1384 times.
✓ Branch 1 taken 1306 times.
|
2690 | if (prepare) { |
| 10101 |
1/2✓ Branch 0 taken 1384 times.
✗ Branch 1 not taken.
|
1384 | error = alter_part->prepare(altered_table, old_part, nullptr); |
| 10102 | } else { | ||
| 10103 |
1/2✓ Branch 0 taken 1291 times.
✗ Branch 1 not taken.
|
1306 | error = alter_part->try_commit(nullptr, altered_table, old_part, nullptr); |
| 10104 | } | ||
| 10105 | |||
| 10106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2675 times.
|
2675 | if (error != 0) { |
| 10107 | ✗ | return (error); | |
| 10108 | } | ||
| 10109 | } | ||
| 10110 | |||
| 10111 | 1754 | return (error); | |
| 10112 | } | ||
| 10113 | |||
| 10114 | /** Determine if one ALTER TABLE can be done instantly on the partitioned table | ||
| 10115 | @param[in] ha_alter_info the DDL operation | ||
| 10116 | @param[in] num_parts number of partitions | ||
| 10117 | @param[in] part_share the partitioned tables | ||
| 10118 | @param[in] old_table old TABLE | ||
| 10119 | @param[in] altered_table new TABLE | ||
| 10120 | @return Instant_Type accordingly */ | ||
| 10121 | 1085 | static inline Instant_Type innopart_support_instant( | |
| 10122 | const Alter_inplace_info *ha_alter_info, uint16_t num_parts, | ||
| 10123 | const Ha_innopart_share *part_share, const TABLE *old_table, | ||
| 10124 | const TABLE *altered_table) { | ||
| 10125 | 1085 | Instant_Type type = Instant_Type::INSTANT_IMPOSSIBLE; | |
| 10126 | |||
| 10127 |
2/2✓ Branch 0 taken 1941 times.
✓ Branch 1 taken 258 times.
|
2199 | for (uint32_t i = 0; i < num_parts; ++i) { |
| 10128 | 3882 | type = innobase_support_instant( | |
| 10129 | 1941 | ha_alter_info, part_share->get_table_part(i), old_table, altered_table); | |
| 10130 |
2/2✓ Branch 0 taken 827 times.
✓ Branch 1 taken 1114 times.
|
1941 | if (type == Instant_Type::INSTANT_IMPOSSIBLE) { |
| 10131 | 827 | return (type); | |
| 10132 | } | ||
| 10133 | } | ||
| 10134 | |||
| 10135 | 258 | return (type); | |
| 10136 | } | ||
| 10137 | |||
| 10138 | ✗ | int ha_innopart::parallel_scan_init(void *&scan_ctx, size_t *num_threads, | |
| 10139 | bool use_reserved_threads) { | ||
| 10140 | ✗ | auto max_threads = thd_parallel_read_threads(m_prebuilt->trx->mysql_thd); | |
| 10141 | ✗ | ut_a(max_threads <= Parallel_reader::MAX_THREADS); | |
| 10142 | |||
| 10143 | ✗ | max_threads = static_cast<ulong>( | |
| 10144 | ✗ | Parallel_reader::available_threads(max_threads, use_reserved_threads)); | |
| 10145 | |||
| 10146 | ✗ | if (max_threads == 0) { | |
| 10147 | ✗ | return (HA_ERR_GENERIC); | |
| 10148 | } | ||
| 10149 | |||
| 10150 | ✗ | scan_ctx = nullptr; | |
| 10151 | |||
| 10152 | ✗ | const auto row_len = m_prebuilt->mysql_row_len; | |
| 10153 | |||
| 10154 | ✗ | auto adapter = ut::new_withkey<Parallel_reader_adapter>( | |
| 10155 | ✗ | UT_NEW_THIS_FILE_PSI_KEY, max_threads, row_len); | |
| 10156 | |||
| 10157 | ✗ | if (adapter == nullptr) { | |
| 10158 | ✗ | Parallel_reader::release_threads(max_threads); | |
| 10159 | ✗ | return (HA_ERR_OUT_OF_MEM); | |
| 10160 | } | ||
| 10161 | |||
| 10162 | ✗ | auto trx = m_prebuilt->trx; | |
| 10163 | |||
| 10164 | ✗ | innobase_register_trx(ht, ha_thd(), trx); | |
| 10165 | |||
| 10166 | ✗ | trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE); | |
| 10167 | |||
| 10168 | ✗ | trx_assign_read_view(trx); | |
| 10169 | |||
| 10170 | ✗ | const Parallel_reader::Scan_range FULL_SCAN{}; | |
| 10171 | ✗ | const auto first_used_partition = m_part_info->get_first_used_partition(); | |
| 10172 | |||
| 10173 | ✗ | for (auto i = first_used_partition; i < m_tot_parts; | |
| 10174 | ✗ | i = m_part_info->get_next_used_partition(i)) { | |
| 10175 | ✗ | set_partition(i); | |
| 10176 | |||
| 10177 | ✗ | if (dict_table_is_discarded(m_prebuilt->table)) { | |
| 10178 | ✗ | ib_senderrf(ha_thd(), IB_LOG_LEVEL_ERROR, ER_TABLESPACE_DISCARDED, | |
| 10179 | ✗ | m_prebuilt->table->name.m_name); | |
| 10180 | |||
| 10181 | ✗ | ut::delete_(adapter); | |
| 10182 | ✗ | return HA_ERR_NO_SUCH_TABLE; | |
| 10183 | } | ||
| 10184 | |||
| 10185 | ✗ | build_template(true); | |
| 10186 | |||
| 10187 | ✗ | Parallel_reader::Config config(FULL_SCAN, m_prebuilt->table->first_index(), | |
| 10188 | ✗ | 0, i); | |
| 10189 | |||
| 10190 | dberr_t err = | ||
| 10191 | ✗ | adapter->add_scan(trx, config, [=](const Parallel_reader::Ctx *ctx) { | |
| 10192 | ✗ | return (adapter->process_rows(ctx)); | |
| 10193 | }); | ||
| 10194 | |||
| 10195 | ✗ | if (err != DB_SUCCESS) { | |
| 10196 | ✗ | ut::delete_(adapter); | |
| 10197 | ✗ | return (convert_error_code_to_mysql(err, 0, ha_thd())); | |
| 10198 | } | ||
| 10199 | } | ||
| 10200 | |||
| 10201 | ✗ | scan_ctx = adapter; | |
| 10202 | ✗ | *num_threads = max_threads; | |
| 10203 | |||
| 10204 | ✗ | adapter->set(m_prebuilt); | |
| 10205 | |||
| 10206 | ✗ | return (0); | |
| 10207 | } | ||
| 10208 | |||
| 10209 | ✗ | int ha_innopart::parallel_scan(void *scan_ctx, void **thread_ctxs, | |
| 10210 | Parallel_reader_adapter::Init_fn init_fn, | ||
| 10211 | Parallel_reader_adapter::Load_fn load_fn, | ||
| 10212 | Parallel_reader_adapter::End_fn end_fn) { | ||
| 10213 | ✗ | auto adapter = static_cast<Parallel_reader_adapter *>(scan_ctx); | |
| 10214 | |||
| 10215 | ✗ | auto err = adapter->run(thread_ctxs, init_fn, load_fn, end_fn); | |
| 10216 | |||
| 10217 | ✗ | return (convert_error_code_to_mysql(err, 0, ha_thd())); | |
| 10218 | } | ||
| 10219 | |||
| 10220 | ✗ | void ha_innopart::parallel_scan_end(void *parallel_scan_ctx) { | |
| 10221 | ✗ | auto adapter = static_cast<Parallel_reader_adapter *>(parallel_scan_ctx); | |
| 10222 | ✗ | ut::delete_(adapter); | |
| 10223 | } | ||
| 10224 | |||
| 10225 | /** Check if InnoDB supports a particular alter table in-place. | ||
| 10226 | @param[in] altered_table TABLE object for new version of table. | ||
| 10227 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 10228 | by ALTER TABLE and holding data used during in-place alter. | ||
| 10229 | @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported | ||
| 10230 | @retval HA_ALTER_INPLACE_NO_LOCK Supported | ||
| 10231 | @retval HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE Supported, but | ||
| 10232 | requires lock during main phase and exclusive lock during prepare | ||
| 10233 | phase. | ||
| 10234 | @retval HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE Supported, prepare | ||
| 10235 | phase requires exclusive lock. */ | ||
| 10236 | 2064 | enum_alter_inplace_result ha_innopart::check_if_supported_inplace_alter( | |
| 10237 | TABLE *altered_table, Alter_inplace_info *ha_alter_info) { | ||
| 10238 |
1/2✓ Branch 0 taken 2064 times.
✗ Branch 1 not taken.
|
2064 | DBUG_TRACE; |
| 10239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2064 times.
|
2064 | assert(ha_alter_info->handler_ctx == nullptr); |
| 10240 | |||
| 10241 | /* Not supporting these for partitioned tables yet! */ | ||
| 10242 | |||
| 10243 | /* | ||
| 10244 | FK not yet supported. SQL-layer blocks most of such changes. | ||
| 10245 | We resort to COPY algorithm for a few which are still allowed | ||
| 10246 | (e.g. REMOVE PARTITIONING and ADD FOREIGN KEY at the same time). | ||
| 10247 | */ | ||
| 10248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2064 times.
|
2064 | if (ha_alter_info->handler_flags & (Alter_inplace_info::ADD_FOREIGN_KEY | |
| 10249 | Alter_inplace_info::DROP_FOREIGN_KEY)) { | ||
| 10250 | ✗ | ha_alter_info->unsupported_reason = | |
| 10251 | ✗ | innobase_get_err_msg(ER_FOREIGN_KEY_ON_PARTITIONED); | |
| 10252 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10253 | } | ||
| 10254 | /* FTS not yet supported either. */ | ||
| 10255 |
2/2✓ Branch 0 taken 300 times.
✓ Branch 1 taken 1764 times.
|
2064 | if ((ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX)) { |
| 10256 |
2/2✓ Branch 0 taken 300 times.
✓ Branch 1 taken 300 times.
|
600 | for (uint i = 0; i < ha_alter_info->index_add_count; i++) { |
| 10257 | 300 | const KEY *key = | |
| 10258 | 300 | &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; | |
| 10259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
|
300 | if (key->flags & HA_FULLTEXT) { |
| 10260 | ✗ | assert(!(key->flags & HA_KEYFLAG_MASK & | |
| 10261 | ~(HA_FULLTEXT | HA_PACK_KEY | HA_GENERATED_KEY | | ||
| 10262 | HA_BINARY_PACK_KEY))); | ||
| 10263 | ✗ | ha_alter_info->unsupported_reason = | |
| 10264 | ✗ | innobase_get_err_msg(ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING); | |
| 10265 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10266 | } | ||
| 10267 | } | ||
| 10268 | } | ||
| 10269 | /* We cannot allow INPLACE to change order of KEY partitioning fields! */ | ||
| 10270 | 4128 | if ((ha_alter_info->handler_flags & | |
| 10271 |
4/4✓ Branch 0 taken 231 times.
✓ Branch 1 taken 1833 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2057 times.
|
2295 | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER) && |
| 10272 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 224 times.
|
231 | !m_part_info->same_key_column_order( |
| 10273 |
1/2✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
|
231 | &ha_alter_info->alter_info->create_list)) { |
| 10274 | 7 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10275 | } | ||
| 10276 | |||
| 10277 | /* Cannot allow INPLACE for drop and create PRIMARY KEY if partition is | ||
| 10278 | on Primary Key - PARTITION BY KEY() */ | ||
| 10279 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2046 times.
|
2057 | if ((ha_alter_info->handler_flags & (Alter_inplace_info::ADD_PK_INDEX | |
| 10280 | Alter_inplace_info::DROP_PK_INDEX))) { | ||
| 10281 | /* Check partition by key(). */ | ||
| 10282 | 33 | if ((m_part_info->part_type == partition_type::HASH) && | |
| 10283 |
7/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 9 times.
|
20 | m_part_info->list_of_part_fields && |
| 10284 | 9 | m_part_info->part_field_list.is_empty()) { | |
| 10285 | 2 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10286 | } | ||
| 10287 | |||
| 10288 | /* Check sub-partition by key(). */ | ||
| 10289 | 18 | if ((m_part_info->subpart_type == partition_type::HASH) && | |
| 10290 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
|
9 | m_part_info->list_of_subpart_fields && |
| 10291 | ✗ | m_part_info->subpart_field_list.is_empty()) { | |
| 10292 | ✗ | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10293 | } | ||
| 10294 | } | ||
| 10295 | |||
| 10296 | /* Check for ALTER TABLE ... PARTITION, following operations can | ||
| 10297 | be done inplace */ | ||
| 10298 |
2/2✓ Branch 0 taken 970 times.
✓ Branch 1 taken 1085 times.
|
2055 | if (alter_parts::apply_to(ha_alter_info)) { |
| 10299 | /* Two meanings here: | ||
| 10300 | 1. ALTER TABLE .. PARTITION could not be combined with | ||
| 10301 | other ALTER TABLE operations; | ||
| 10302 | 2. Only one operation of ALTER TABLE .. PARTITION can be | ||
| 10303 | done in single statement. Only exception is that | ||
| 10304 | 'ALTER TABLE table REORGANIZE PARTITION' for HASH/KEY | ||
| 10305 | partitions. This will flag both COALESCE_PARTITION | ||
| 10306 | and ALTER_TABLE_REORG; | ||
| 10307 | The ALTER_ALL_PARTITION should be screened out, which could only | ||
| 10308 | be set along with the REBUILD PARTITION */ | ||
| 10309 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 970 times.
|
970 | ut_ad(is_single_bit(ha_alter_info->handler_flags & |
| 10310 | ~Alter_inplace_info::ALTER_ALL_PARTITION) || | ||
| 10311 | ha_alter_info->handler_flags == | ||
| 10312 | (Alter_inplace_info::COALESCE_PARTITION | | ||
| 10313 | Alter_inplace_info::ALTER_TABLE_REORG)); | ||
| 10314 |
4/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 964 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 970 times.
|
970 | ut_ad(!(ha_alter_info->handler_flags & |
| 10315 | Alter_inplace_info::ALTER_ALL_PARTITION) || | ||
| 10316 | (ha_alter_info->handler_flags & | ||
| 10317 | Alter_inplace_info::ALTER_REBUILD_PARTITION)); | ||
| 10318 | |||
| 10319 |
3/4✓ Branch 0 taken 970 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 613 times.
✓ Branch 3 taken 357 times.
|
970 | if (alter_parts::need_copy(ha_alter_info)) { |
| 10320 | 613 | return HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE; | |
| 10321 | } else { | ||
| 10322 | 357 | return HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE; | |
| 10323 | } | ||
| 10324 | } | ||
| 10325 | |||
| 10326 | 2170 | Instant_Type instant_type = innopart_support_instant( | |
| 10327 |
1/2✓ Branch 0 taken 1085 times.
✗ Branch 1 not taken.
|
1085 | ha_alter_info, m_tot_parts, m_part_share, this->table, altered_table); |
| 10328 | 1085 | ha_alter_info->handler_trivial_ctx = | |
| 10329 | 1085 | instant_type_to_int(Instant_Type::INSTANT_IMPOSSIBLE); | |
| 10330 | |||
| 10331 |
3/4✓ Branch 0 taken 827 times.
✓ Branch 1 taken 255 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
1085 | switch (instant_type) { |
| 10332 | 827 | case Instant_Type::INSTANT_IMPOSSIBLE: | |
| 10333 | 827 | break; | |
| 10334 | 255 | case Instant_Type::INSTANT_ADD_DROP_COLUMN: | |
| 10335 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 248 times.
|
255 | if (ha_alter_info->alter_info->requested_algorithm == |
| 10336 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE) { | ||
| 10337 | 7 | break; | |
| 10338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
|
248 | } else if (m_prebuilt->table->n_def == REC_MAX_N_FIELDS) { |
| 10339 | ✗ | if (ha_alter_info->alter_info->requested_algorithm == | |
| 10340 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 10341 | ✗ | my_error(ER_TOO_MANY_FIELDS, MYF(0), m_prebuilt->table->name.m_name); | |
| 10342 | ✗ | return HA_ALTER_ERROR; | |
| 10343 | } | ||
| 10344 | /* INSTANT can't be done any more. Fall back to INPLACE. */ | ||
| 10345 | ✗ | break; | |
| 10346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
|
248 | } else if (m_prebuilt->table->current_row_version == MAX_ROW_VERSION) { |
| 10347 | ✗ | if (ha_alter_info->alter_info->requested_algorithm == | |
| 10348 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 10349 | ✗ | my_error(ER_INNODB_MAX_ROW_VERSION, MYF(0), | |
| 10350 | ✗ | m_prebuilt->table->name.m_name); | |
| 10351 | ✗ | return HA_ALTER_ERROR; | |
| 10352 | } | ||
| 10353 | /* INSTANT can't be done any more. Fall back to INPLACE. */ | ||
| 10354 | ✗ | break; | |
| 10355 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 244 times.
|
248 | } else if (!Instant_ddl_impl<dd::Table>::is_instant_add_possible( |
| 10356 |
1/2✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
|
248 | ha_alter_info, table, altered_table, m_prebuilt->table)) { |
| 10357 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (ha_alter_info->alter_info->requested_algorithm == |
| 10358 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 10359 | /* Try to find if after adding columns, any possible row stays | ||
| 10360 | within permissible limit. If it doesn't, return error. */ | ||
| 10361 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_INNODB_INSTANT_ADD_NOT_SUPPORTED_MAX_SIZE, MYF(0)); |
| 10362 | 4 | return HA_ALTER_ERROR; | |
| 10363 | } | ||
| 10364 | |||
| 10365 | /* INSTANT can't be done. Fall back to INPLACE. */ | ||
| 10366 | ✗ | break; | |
| 10367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
|
244 | } else if (ha_alter_info->error_if_not_empty) { |
| 10368 | /* In this case, it can't be instant because the table | ||
| 10369 | may not be empty. Have to fall back to INPLACE */ | ||
| 10370 | ✗ | break; | |
| 10371 | } | ||
| 10372 | [[fallthrough]]; | ||
| 10373 | case Instant_Type::INSTANT_NO_CHANGE: | ||
| 10374 | case Instant_Type::INSTANT_VIRTUAL_ONLY: | ||
| 10375 | case Instant_Type::INSTANT_COLUMN_RENAME: | ||
| 10376 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 246 times.
|
247 | if (altered_table->s->fields > REC_MAX_N_USER_FIELDS) { |
| 10377 | /* Deny the inplace ALTER TABLE. MySQL will try to | ||
| 10378 | re-create the table and ha_innobase::create() will | ||
| 10379 | return an error too. This is how we effectively | ||
| 10380 | deny adding too many columns to a table. */ | ||
| 10381 | 1 | ha_alter_info->unsupported_reason = | |
| 10382 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | innobase_get_err_msg(ER_TOO_MANY_FIELDS); |
| 10383 | 1 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 10384 | } | ||
| 10385 | |||
| 10386 | 246 | ha_alter_info->handler_trivial_ctx = instant_type_to_int(instant_type); | |
| 10387 | 246 | return HA_ALTER_INPLACE_INSTANT; | |
| 10388 | } | ||
| 10389 | |||
| 10390 | /* Check for PK and UNIQUE should already be done when creating the | ||
| 10391 | new table metadata. | ||
| 10392 | (fix_partition_info/check_primary_key+check_unique_key) */ | ||
| 10393 | |||
| 10394 |
1/2✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
|
834 | set_partition(0); |
| 10395 |
1/2✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
|
834 | return ha_innobase::check_if_supported_inplace_alter(altered_table, |
| 10396 | 834 | ha_alter_info); | |
| 10397 | 2064 | } | |
| 10398 | |||
| 10399 | /** Prepare in-place ALTER for table. | ||
| 10400 | Allows InnoDB to update internal structures with concurrent | ||
| 10401 | writes blocked (provided that check_if_supported_inplace_alter() | ||
| 10402 | did not return HA_ALTER_INPLACE_NO_LOCK). | ||
| 10403 | This will be invoked before inplace_alter_table(). | ||
| 10404 | @param[in] altered_table TABLE object for new version of table. | ||
| 10405 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 10406 | by ALTER TABLE and holding data used during in-place alter. | ||
| 10407 | @param[in] old_table_def dd::Table object describing old | ||
| 10408 | version of the table. | ||
| 10409 | @param[in,out] new_table_def dd::Table object for the new version | ||
| 10410 | of the table. Can be adjusted by this call. Changes to the table | ||
| 10411 | definition will be persisted in the data-dictionary at statement | ||
| 10412 | commit time. | ||
| 10413 | @retval true Failure. | ||
| 10414 | @retval false Success. */ | ||
| 10415 | 1985 | bool ha_innopart::prepare_inplace_alter_table(TABLE *altered_table, | |
| 10416 | Alter_inplace_info *ha_alter_info, | ||
| 10417 | const dd::Table *old_table_def, | ||
| 10418 | dd::Table *new_table_def) { | ||
| 10419 |
1/2✓ Branch 0 taken 1985 times.
✗ Branch 1 not taken.
|
1985 | DBUG_TRACE; |
| 10420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1985 times.
|
1985 | assert(ha_alter_info->handler_ctx == nullptr); |
| 10421 | |||
| 10422 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1983 times.
|
1985 | if (tablespace_is_shared_space(ha_alter_info->create_info)) { |
| 10423 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION, PARTITION_IN_SHARED_TABLESPACE, |
| 10424 | MYF(0)); | ||
| 10425 | 2 | return true; | |
| 10426 | } | ||
| 10427 | |||
| 10428 | /* The row format in new table may differ from the old one, | ||
| 10429 | which is set by server earlier. So keep them the same */ | ||
| 10430 |
2/4✓ Branch 0 taken 1983 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1983 times.
✗ Branch 3 not taken.
|
1983 | new_table_def->set_row_format(old_table_def->row_format()); |
| 10431 | |||
| 10432 |
2/2✓ Branch 0 taken 554 times.
✓ Branch 1 taken 1429 times.
|
1983 | if (altered_table->found_next_number_field != nullptr) { |
| 10433 |
2/4✓ Branch 0 taken 554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 554 times.
✗ Branch 3 not taken.
|
554 | dd_copy_autoinc(old_table_def->se_private_data(), |
| 10434 |
1/2✓ Branch 0 taken 554 times.
✗ Branch 1 not taken.
|
554 | new_table_def->se_private_data()); |
| 10435 | } | ||
| 10436 | |||
| 10437 |
2/2✓ Branch 0 taken 943 times.
✓ Branch 1 taken 1040 times.
|
1983 | if (alter_parts::apply_to(ha_alter_info)) { |
| 10438 |
1/2✓ Branch 0 taken 868 times.
✗ Branch 1 not taken.
|
943 | return prepare_inplace_alter_partition(altered_table, ha_alter_info, |
| 10439 | 868 | old_table_def, new_table_def); | |
| 10440 | } | ||
| 10441 | |||
| 10442 | ha_innopart_inplace_ctx *ctx_parts; | ||
| 10443 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | THD *thd = ha_thd(); |
| 10444 | 1040 | bool res = true; | |
| 10445 | |||
| 10446 | /* Clean up all ins/upd nodes. */ | ||
| 10447 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | clear_ins_upd_nodes(); |
| 10448 | /* | ||
| 10449 | This object will be freed by server, so always use 'new' | ||
| 10450 | and there is no need to free on failure */ | ||
| 10451 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | ctx_parts = new (thd->mem_root) ha_innopart_inplace_ctx(m_tot_parts); |
| 10452 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1040 times.
|
1040 | if (ctx_parts == nullptr) { |
| 10453 | ✗ | return HA_ALTER_ERROR; | |
| 10454 | } | ||
| 10455 | |||
| 10456 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | ctx_parts->ctx_array = ut::new_arr_withkey<inplace_alter_handler_ctx *>( |
| 10457 | 1040 | UT_NEW_THIS_FILE_PSI_KEY, ut::Count{m_tot_parts + 1}); | |
| 10458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1040 times.
|
1040 | if (ctx_parts->ctx_array == nullptr) { |
| 10459 | ✗ | return HA_ALTER_ERROR; | |
| 10460 | } | ||
| 10461 | |||
| 10462 | 1040 | memset(ctx_parts->ctx_array, 0, | |
| 10463 | 1040 | sizeof(inplace_alter_handler_ctx *) * (m_tot_parts + 1)); | |
| 10464 | |||
| 10465 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | ctx_parts->m_old_info = ut::new_arr_withkey<alter_table_old_info_t>( |
| 10466 | 1040 | UT_NEW_THIS_FILE_PSI_KEY, ut::Count{m_tot_parts}); | |
| 10467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1040 times.
|
1040 | if (ctx_parts->m_old_info == nullptr) { |
| 10468 | ✗ | return HA_ALTER_ERROR; | |
| 10469 | } | ||
| 10470 | |||
| 10471 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | ctx_parts->prebuilt_array = ut::new_arr_withkey<row_prebuilt_t *>( |
| 10472 | 1040 | UT_NEW_THIS_FILE_PSI_KEY, ut::Count{m_tot_parts}); | |
| 10473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1040 times.
|
1040 | if (ctx_parts->prebuilt_array == nullptr) { |
| 10474 | ✗ | return HA_ALTER_ERROR; | |
| 10475 | } | ||
| 10476 | /* For the first partition use the current prebuilt. */ | ||
| 10477 | 1040 | ctx_parts->prebuilt_array[0] = m_prebuilt; | |
| 10478 | /* Create new prebuilt for the rest of the partitions. | ||
| 10479 | It is needed for the current implementation of | ||
| 10480 | ha_innobase::commit_inplace_alter_table(). */ | ||
| 10481 |
2/2✓ Branch 0 taken 3365 times.
✓ Branch 1 taken 1040 times.
|
4405 | for (uint i = 1; i < m_tot_parts; i++) { |
| 10482 | row_prebuilt_t *tmp_prebuilt; | ||
| 10483 |
1/2✓ Branch 0 taken 3365 times.
✗ Branch 1 not taken.
|
3365 | tmp_prebuilt = row_create_prebuilt(m_part_share->get_table_part(i), |
| 10484 |
1/2✓ Branch 0 taken 3365 times.
✗ Branch 1 not taken.
|
3365 | table_share->reclength); |
| 10485 | /* Use same trx as original prebuilt. */ | ||
| 10486 | 3365 | tmp_prebuilt->trx = m_prebuilt->trx; | |
| 10487 | 3365 | ctx_parts->prebuilt_array[i] = tmp_prebuilt; | |
| 10488 | } | ||
| 10489 | |||
| 10490 |
2/2✓ Branch 0 taken 315 times.
✓ Branch 1 taken 725 times.
|
1040 | if (altered_table->found_next_number_field != nullptr) { |
| 10491 |
1/2✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
|
315 | dd_set_autoinc(new_table_def->se_private_data(), |
| 10492 |
1/2✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
|
315 | ha_alter_info->create_info->auto_increment_value); |
| 10493 | } | ||
| 10494 | |||
| 10495 | 1040 | const char *save_tablespace = ha_alter_info->create_info->tablespace; | |
| 10496 | |||
| 10497 | 1040 | const char *save_data_file_name = ha_alter_info->create_info->data_file_name; | |
| 10498 | |||
| 10499 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | auto oldp = old_table_def->leaf_partitions().begin(); |
| 10500 |
1/2✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
|
1040 | auto newp = new_table_def->leaf_partitions()->begin(); |
| 10501 | |||
| 10502 |
2/2✓ Branch 0 taken 4311 times.
✓ Branch 1 taken 946 times.
|
5257 | for (uint i = 0; i < m_tot_parts; ++oldp, ++newp) { |
| 10503 | 4311 | m_prebuilt = ctx_parts->prebuilt_array[i]; | |
| 10504 |
1/2✓ Branch 0 taken 4311 times.
✗ Branch 1 not taken.
|
4311 | set_partition(i); |
| 10505 | |||
| 10506 | 4311 | const dd::Partition *old_part = *oldp; | |
| 10507 | 4311 | dd::Partition *new_part = *newp; | |
| 10508 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4311 times.
|
4311 | ut_ad(old_part != nullptr); |
| 10509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4311 times.
|
4311 | ut_ad(new_part != nullptr); |
| 10510 | |||
| 10511 | /* We exempt this asserion when we do inplace during copy algorithm (ie. | ||
| 10512 | during expanded fast index creation). This is OK because we are using an | ||
| 10513 | intermediate table created during ALTER COPY algorithm. Hence | ||
| 10514 | m_prebuilt->table->id is newer than the original id stored in DD */ | ||
| 10515 |
3/8✓ Branch 0 taken 4311 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4311 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4311 times.
|
4311 | ut_ad(m_prebuilt->table->id == old_part->se_private_id() || |
| 10516 | m_prebuilt->table->skip_alter_undo); | ||
| 10517 | |||
| 10518 | 4311 | ha_alter_info->handler_ctx = nullptr; | |
| 10519 | |||
| 10520 | /* Set the tablespace and data_file_name value of the | ||
| 10521 | alter_info to the tablespace and data_file_name value | ||
| 10522 | that was existing for the partition originally, so that | ||
| 10523 | for ALTER TABLE the tablespace clause in create option | ||
| 10524 | is ignored for existing partitions, and later set it | ||
| 10525 | back to its old value */ | ||
| 10526 | |||
| 10527 | 4311 | ha_alter_info->create_info->tablespace = m_prebuilt->table->tablespace; | |
| 10528 | 4311 | ha_alter_info->create_info->data_file_name = | |
| 10529 | 4311 | m_prebuilt->table->data_dir_path; | |
| 10530 | |||
| 10531 |
1/2✓ Branch 0 taken 4221 times.
✗ Branch 1 not taken.
|
4311 | res = prepare_inplace_alter_table_impl<dd::Partition>( |
| 10532 | altered_table, ha_alter_info, old_part, new_part); | ||
| 10533 | |||
| 10534 |
1/2✓ Branch 0 taken 4221 times.
✗ Branch 1 not taken.
|
4221 | update_partition(i); |
| 10535 | 4221 | ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx; | |
| 10536 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4217 times.
|
4221 | if (res) { |
| 10537 | 4 | break; | |
| 10538 | } | ||
| 10539 | |||
| 10540 | 4217 | ha_innobase_inplace_ctx *ctx = | |
| 10541 | 4217 | static_cast<ha_innobase_inplace_ctx *>(ctx_parts->ctx_array[i]); | |
| 10542 |
2/2✓ Branch 0 taken 3150 times.
✓ Branch 1 taken 1067 times.
|
4217 | if (ctx != nullptr) { |
| 10543 | 3150 | ctx_parts->m_old_info[i].update(ctx->old_table, ctx->need_rebuild()); | |
| 10544 | } | ||
| 10545 | |||
| 10546 | 4217 | ++i; | |
| 10547 | } | ||
| 10548 | |||
| 10549 | 950 | m_prebuilt = ctx_parts->prebuilt_array[0]; | |
| 10550 | 950 | ha_alter_info->handler_ctx = ctx_parts; | |
| 10551 | 950 | ha_alter_info->group_commit_ctx = ctx_parts->ctx_array; | |
| 10552 | 950 | ha_alter_info->create_info->tablespace = save_tablespace; | |
| 10553 | 950 | ha_alter_info->create_info->data_file_name = save_data_file_name; | |
| 10554 | |||
| 10555 | 950 | return res; | |
| 10556 | 1820 | } | |
| 10557 | |||
| 10558 | 1801 | bool ha_innopart::inplace_alter_table(TABLE *altered_table, | |
| 10559 | Alter_inplace_info *ha_alter_info, | ||
| 10560 | const dd::Table *old_table_def, | ||
| 10561 | dd::Table *new_table_def) { | ||
| 10562 |
2/2✓ Branch 0 taken 855 times.
✓ Branch 1 taken 946 times.
|
1801 | if (alter_parts::apply_to(ha_alter_info)) { |
| 10563 |
1/2✓ Branch 0 taken 855 times.
✗ Branch 1 not taken.
|
855 | return (inplace_alter_partition(ha_alter_info)); |
| 10564 | } | ||
| 10565 | |||
| 10566 | 946 | bool res = true; | |
| 10567 | ha_innopart_inplace_ctx *ctx_parts; | ||
| 10568 | |||
| 10569 | 946 | ctx_parts = | |
| 10570 | static_cast<ha_innopart_inplace_ctx *>(ha_alter_info->handler_ctx); | ||
| 10571 | |||
| 10572 | /* It could be not allocated at all */ | ||
| 10573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 946 times.
|
946 | if (ctx_parts == nullptr) { |
| 10574 | ✗ | return (false); | |
| 10575 | } | ||
| 10576 | |||
| 10577 |
1/2✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
|
946 | auto oldp = old_table_def->leaf_partitions().begin(); |
| 10578 |
1/2✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
|
946 | auto newp = new_table_def->leaf_partitions()->begin(); |
| 10579 | |||
| 10580 |
2/2✓ Branch 0 taken 4127 times.
✓ Branch 1 taken 944 times.
|
5071 | for (uint i = 0; i < m_tot_parts; ++oldp, ++newp) { |
| 10581 | 4127 | m_prebuilt = ctx_parts->prebuilt_array[i]; | |
| 10582 | 4127 | ha_alter_info->handler_ctx = ctx_parts->ctx_array[i]; | |
| 10583 |
1/2✓ Branch 0 taken 4127 times.
✗ Branch 1 not taken.
|
4127 | set_partition(i); |
| 10584 |
4/4✓ Branch 0 taken 3181 times.
✓ Branch 1 taken 946 times.
✓ Branch 2 taken 2360 times.
✓ Branch 3 taken 821 times.
|
4127 | if (i != 0 && ha_alter_info->handler_ctx != nullptr) { |
| 10585 |
1/2✓ Branch 0 taken 2360 times.
✗ Branch 1 not taken.
|
2360 | ha_alter_info->handler_ctx->set_shared_data(ctx_parts->ctx_array[i - 1]); |
| 10586 | } | ||
| 10587 | |||
| 10588 |
1/2✓ Branch 0 taken 4127 times.
✗ Branch 1 not taken.
|
4127 | res = inplace_alter_table_impl<dd::Partition>(altered_table, ha_alter_info); |
| 10589 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4127 times.
|
4127 | ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx); |
| 10590 | 4127 | ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx; | |
| 10591 | |||
| 10592 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4125 times.
|
4127 | if (res) { |
| 10593 | 2 | break; | |
| 10594 | } | ||
| 10595 | |||
| 10596 | 4125 | ++i; | |
| 10597 | } | ||
| 10598 | 946 | m_prebuilt = ctx_parts->prebuilt_array[0]; | |
| 10599 | 946 | ha_alter_info->handler_ctx = ctx_parts; | |
| 10600 | 946 | return (res); | |
| 10601 | } | ||
| 10602 | |||
| 10603 | /** Commit or rollback. | ||
| 10604 | Commit or rollback the changes made during | ||
| 10605 | prepare_inplace_alter_table() and inplace_alter_table() inside | ||
| 10606 | the storage engine. Note that the allowed level of concurrency | ||
| 10607 | during this operation will be the same as for | ||
| 10608 | inplace_alter_table() and thus might be higher than during | ||
| 10609 | prepare_inplace_alter_table(). (E.g concurrent writes were | ||
| 10610 | blocked during prepare, but might not be during commit). | ||
| 10611 | @param[in] altered_table TABLE object for new version of table. | ||
| 10612 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 10613 | by ALTER TABLE and holding data used during | ||
| 10614 | in-place alter. | ||
| 10615 | @param[in] commit true => Commit, false => Rollback. | ||
| 10616 | @param[in] old_table_def dd::Table object describing old | ||
| 10617 | version of the table. | ||
| 10618 | @param[in,out] new_table_def dd::Table object for the new version | ||
| 10619 | of the table. Can be adjusted by this call. Changes to the table | ||
| 10620 | definition will be persisted in the data-dictionary at statement | ||
| 10621 | commit time. | ||
| 10622 | @retval true Failure. | ||
| 10623 | @retval false Success. */ | ||
| 10624 | 1820 | bool ha_innopart::commit_inplace_alter_table(TABLE *altered_table, | |
| 10625 | Alter_inplace_info *ha_alter_info, | ||
| 10626 | bool commit, | ||
| 10627 | const dd::Table *old_table_def, | ||
| 10628 | dd::Table *new_table_def) { | ||
| 10629 |
2/2✓ Branch 0 taken 868 times.
✓ Branch 1 taken 952 times.
|
1820 | if (alter_parts::apply_to(ha_alter_info)) { |
| 10630 | 868 | return (commit_inplace_alter_partition(altered_table, ha_alter_info, commit, | |
| 10631 | 818 | old_table_def, new_table_def)); | |
| 10632 | } | ||
| 10633 | |||
| 10634 | 952 | ha_innopart_inplace_ctx *ctx_parts = | |
| 10635 | static_cast<ha_innopart_inplace_ctx *>(ha_alter_info->handler_ctx); | ||
| 10636 | |||
| 10637 | /* It could be not allocated at all */ | ||
| 10638 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 950 times.
|
952 | if (ctx_parts == nullptr) { |
| 10639 | 2 | return (false); | |
| 10640 | } | ||
| 10641 | |||
| 10642 | 950 | bool res = false; | |
| 10643 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 950 times.
|
950 | ut_ad(ctx_parts->ctx_array != nullptr); |
| 10644 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 950 times.
|
950 | ut_ad(ctx_parts->prebuilt_array != nullptr); |
| 10645 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 950 times.
|
950 | ut_ad(ctx_parts->prebuilt_array[0] == m_prebuilt); |
| 10646 | |||
| 10647 |
2/2✓ Branch 0 taken 944 times.
✓ Branch 1 taken 6 times.
|
950 | if (commit) { |
| 10648 | /* Commit is done through first partition (group commit). */ | ||
| 10649 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 944 times.
|
944 | ut_ad(ha_alter_info->group_commit_ctx == ctx_parts->ctx_array); |
| 10650 | 944 | ha_alter_info->handler_ctx = ctx_parts->ctx_array[0]; | |
| 10651 | 944 | set_partition(0); | |
| 10652 | |||
| 10653 | 944 | res = ha_innobase::commit_inplace_alter_table_impl<dd::Table>( | |
| 10654 | altered_table, ha_alter_info, commit, new_table_def); | ||
| 10655 |
3/6✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 883 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 883 times.
|
883 | ut_ad(res || !ha_alter_info->group_commit_ctx); |
| 10656 | |||
| 10657 | 883 | goto end; | |
| 10658 | } | ||
| 10659 | |||
| 10660 | /* Rollback is done for each partition. */ | ||
| 10661 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (uint i = 0; i < m_tot_parts; i++) { |
| 10662 | 12 | m_prebuilt = ctx_parts->prebuilt_array[i]; | |
| 10663 | 12 | ha_alter_info->handler_ctx = ctx_parts->ctx_array[i]; | |
| 10664 | 12 | set_partition(i); | |
| 10665 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (ha_innobase::commit_inplace_alter_table_impl<dd::Table>( |
| 10666 | altered_table, ha_alter_info, commit, new_table_def)) { | ||
| 10667 | ✗ | res = true; | |
| 10668 | } | ||
| 10669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx); |
| 10670 | 12 | ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx; | |
| 10671 | } | ||
| 10672 | 6 | end: | |
| 10673 | /* All are done successfully, now write back metadata to DD */ | ||
| 10674 |
3/4✓ Branch 0 taken 883 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 883 times.
✗ Branch 3 not taken.
|
889 | if (commit && !res) { |
| 10675 |
4/6✓ Branch 0 taken 246 times.
✓ Branch 1 taken 637 times.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 883 times.
|
883 | ut_ad(!(is_instant(ha_alter_info) && ctx_parts->m_old_info[0].m_rebuild)); |
| 10676 | |||
| 10677 |
1/2✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
|
883 | auto oldp = old_table_def->leaf_partitions().begin(); |
| 10678 |
1/2✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
|
883 | auto newp = new_table_def->leaf_partitions()->begin(); |
| 10679 | 883 | bool inplace_instant = false; | |
| 10680 | |||
| 10681 |
2/2✓ Branch 0 taken 3940 times.
✓ Branch 1 taken 883 times.
|
4823 | for (uint i = 0; i < m_tot_parts; ++oldp, ++newp) { |
| 10682 | 3940 | const dd::Partition *old_part = *oldp; | |
| 10683 | 3940 | dd::Partition *new_part = *newp; | |
| 10684 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3940 times.
|
3940 | ut_ad(old_part != nullptr); |
| 10685 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3940 times.
|
3940 | ut_ad(new_part != nullptr); |
| 10686 | |||
| 10687 | 3940 | ha_innobase_inplace_ctx *ctx = | |
| 10688 | 3940 | static_cast<ha_innobase_inplace_ctx *>(ctx_parts->ctx_array[i]); | |
| 10689 | |||
| 10690 |
2/2✓ Branch 0 taken 1067 times.
✓ Branch 1 taken 2873 times.
|
3940 | if (is_instant(ha_alter_info)) { |
| 10691 | Instant_ddl_impl<dd::Partition> executor( | ||
| 10692 | 1067 | ha_alter_info, m_user_thd, m_prebuilt->trx, | |
| 10693 | 1067 | m_part_share->get_table_part(i), table, altered_table, old_part, | |
| 10694 | new_part, | ||
| 10695 | 1067 | altered_table->found_next_number_field != nullptr | |
| 10696 | 57 | ? reinterpret_cast<uint64_t *>(&m_part_share->next_auto_inc_val) | |
| 10697 |
3/4✓ Branch 0 taken 57 times.
✓ Branch 1 taken 1010 times.
✓ Branch 2 taken 1067 times.
✗ Branch 3 not taken.
|
1067 | : nullptr); |
| 10698 | |||
| 10699 | /* Execute Instant DDL */ | ||
| 10700 |
1/2✓ Branch 0 taken 1067 times.
✗ Branch 1 not taken.
|
1067 | executor.commit_instant_ddl(); |
| 10701 |
2/4✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2873 times.
|
3940 | } else if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) || |
| 10702 | ctx == nullptr) { | ||
| 10703 | ✗ | dd_commit_inplace_no_change(ha_alter_info, old_part, new_part, true); | |
| 10704 | } else { | ||
| 10705 | 2873 | inplace_instant = !ctx_parts->m_old_info[0].m_rebuild; | |
| 10706 | |||
| 10707 | /* Table is not rebuilt so copy instant metadata. | ||
| 10708 | NOTE : To be done only for first partition */ | ||
| 10709 |
4/4✓ Branch 0 taken 637 times.
✓ Branch 1 taken 2236 times.
✓ Branch 2 taken 130 times.
✓ Branch 3 taken 507 times.
|
2873 | if (i == 0 && inplace_instant) { |
| 10710 | 130 | dd_inplace_alter_copy_instant_metadata( | |
| 10711 |
1/2✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
|
130 | ha_alter_info, &old_part->table(), |
| 10712 |
2/4✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
|
130 | const_cast<dd::Table *>(&new_part->table())); |
| 10713 | } | ||
| 10714 | |||
| 10715 |
1/2✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
|
2873 | dd_commit_inplace_alter_table(ctx_parts->m_old_info[i], ctx->new_table, |
| 10716 | old_part, new_part); | ||
| 10717 | } | ||
| 10718 | |||
| 10719 | 3940 | ++i; | |
| 10720 | } | ||
| 10721 | |||
| 10722 | #ifdef UNIV_DEBUG | ||
| 10723 |
1/2✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
|
883 | if (!res) { |
| 10724 |
5/6✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 193 times.
✓ Branch 3 taken 690 times.
✓ Branch 4 taken 193 times.
✓ Branch 5 taken 690 times.
|
1076 | if (dd_table_has_instant_cols(*old_table_def) && |
| 10725 |
1/2✓ Branch 0 taken 193 times.
✗ Branch 1 not taken.
|
193 | !ctx_parts->m_old_info[0].m_rebuild) { |
| 10726 |
2/4✓ Branch 0 taken 193 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 193 times.
|
193 | ut_ad(dd_table_has_instant_cols(*new_table_def)); |
| 10727 | } | ||
| 10728 | |||
| 10729 | 883 | uint i = 0; | |
| 10730 |
3/4✓ Branch 0 taken 883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3940 times.
✓ Branch 3 taken 883 times.
|
4823 | for (auto part : *new_table_def->leaf_partitions()) { |
| 10731 | ha_innobase_inplace_ctx *ctx = | ||
| 10732 | 3940 | static_cast<ha_innobase_inplace_ctx *>(ctx_parts->ctx_array[i++]); | |
| 10733 |
2/2✓ Branch 0 taken 2873 times.
✓ Branch 1 taken 1067 times.
|
3940 | if (ctx != nullptr) { |
| 10734 |
2/4✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2873 times.
|
2873 | ut_ad(dd_table_match(ctx->new_table, part)); |
| 10735 | } | ||
| 10736 | } | ||
| 10737 | } | ||
| 10738 | #endif /* univ_debug */ | ||
| 10739 | } | ||
| 10740 | |||
| 10741 | /* Move the ownership of the new tables back to the m_part_share. */ | ||
| 10742 | ha_innobase_inplace_ctx *ctx; | ||
| 10743 |
2/2✓ Branch 0 taken 3127 times.
✓ Branch 1 taken 639 times.
|
3766 | for (uint i = 0; i < m_tot_parts; i++) { |
| 10744 | /* TODO: Fix to only use one prebuilt (i.e. make inplace | ||
| 10745 | alter partition aware instead of using multiple prebuilt | ||
| 10746 | copies... */ | ||
| 10747 | 3127 | ctx = static_cast<ha_innobase_inplace_ctx *>(ctx_parts->ctx_array[i]); | |
| 10748 |
2/2✓ Branch 0 taken 2877 times.
✓ Branch 1 taken 250 times.
|
3127 | if (ctx != nullptr) { |
| 10749 | 2877 | m_part_share->set_table_part(i, ctx->prebuilt->table); | |
| 10750 | 2877 | ctx->prebuilt->table = nullptr; | |
| 10751 | 2877 | ctx_parts->prebuilt_array[i] = ctx->prebuilt; | |
| 10752 | } else { | ||
| 10753 | 250 | break; | |
| 10754 | } | ||
| 10755 | } | ||
| 10756 | /* The above juggling of prebuilt must be reset here. */ | ||
| 10757 | 889 | m_prebuilt = ctx_parts->prebuilt_array[0]; | |
| 10758 | 889 | m_prebuilt->table = m_part_share->get_table_part(0); | |
| 10759 | 889 | ha_alter_info->handler_ctx = ctx_parts; | |
| 10760 | 889 | return (res); | |
| 10761 | } | ||
| 10762 | |||
| 10763 | /** Create the Altered_partitoins object | ||
| 10764 | @param[in] ha_alter_info thd DDL operation | ||
| 10765 | @retval true On failure | ||
| 10766 | @retval false On success */ | ||
| 10767 | 593 | bool ha_innopart::prepare_for_copy_partitions( | |
| 10768 | Alter_inplace_info *ha_alter_info) { | ||
| 10769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 593 times.
|
593 | ut_ad(m_new_partitions == nullptr); |
| 10770 |
2/4✓ Branch 0 taken 593 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 593 times.
|
593 | ut_ad(alter_parts::need_copy(ha_alter_info)); |
| 10771 | |||
| 10772 | 593 | uint num_parts = ha_alter_info->modified_part_info->num_parts; | |
| 10773 | 593 | uint total_parts = num_parts; | |
| 10774 | |||
| 10775 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 527 times.
|
593 | if (ha_alter_info->modified_part_info->is_sub_partitioned()) { |
| 10776 | 66 | total_parts *= ha_alter_info->modified_part_info->num_subparts; | |
| 10777 | } | ||
| 10778 | |||
| 10779 |
1/2✓ Branch 0 taken 593 times.
✗ Branch 1 not taken.
|
593 | m_new_partitions = ut::new_withkey<Altered_partitions>( |
| 10780 | ut::make_psi_memory_key(mem_key_partitioning), total_parts); | ||
| 10781 | |||
| 10782 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 593 times.
|
593 | if (m_new_partitions == nullptr) { |
| 10783 | ✗ | return (true); | |
| 10784 |
2/4✓ Branch 0 taken 593 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 593 times.
|
593 | } else if (m_new_partitions->initialize()) { |
| 10785 | ✗ | ut::delete_(m_new_partitions); | |
| 10786 | ✗ | m_new_partitions = nullptr; | |
| 10787 | ✗ | return (true); | |
| 10788 | } | ||
| 10789 | |||
| 10790 | 593 | return (false); | |
| 10791 | } | ||
| 10792 | |||
| 10793 | /** write row to new partition. | ||
| 10794 | @param[in] new_part New partition to write to. | ||
| 10795 | @return 0 for success else error code. */ | ||
| 10796 | 2687 | int ha_innopart::write_row_in_new_part(uint new_part) { | |
| 10797 | int result; | ||
| 10798 |
1/2✓ Branch 0 taken 2687 times.
✗ Branch 1 not taken.
|
2687 | DBUG_TRACE; |
| 10799 | |||
| 10800 | 2687 | m_last_part = new_part; | |
| 10801 |
3/4✓ Branch 0 taken 2687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2682 times.
|
2687 | if (m_new_partitions->part(new_part) == nullptr) { |
| 10802 | /* Altered partition contains misplaced row. */ | ||
| 10803 | 5 | m_err_rec = table->record[0]; | |
| 10804 | 5 | return HA_ERR_ROW_IN_WRONG_PARTITION; | |
| 10805 | } | ||
| 10806 | |||
| 10807 |
1/2✓ Branch 0 taken 2682 times.
✗ Branch 1 not taken.
|
2682 | m_new_partitions->prepare_write(m_prebuilt, new_part); |
| 10808 |
1/2✓ Branch 0 taken 2682 times.
✗ Branch 1 not taken.
|
2682 | result = ha_innobase::write_row(table->record[0]); |
| 10809 |
1/2✓ Branch 0 taken 2682 times.
✗ Branch 1 not taken.
|
2682 | m_new_partitions->finish_write(m_prebuilt, new_part); |
| 10810 | 2682 | return result; | |
| 10811 | 2687 | } | |
| 10812 | |||
| 10813 | /** Allows InnoDB to update internal structures with concurrent | ||
| 10814 | writes blocked (given that check_if_supported_inplace_alter() | ||
| 10815 | did not return HA_ALTER_INPLACE_NO_LOCK). | ||
| 10816 | This is for 'ALTER TABLE ... PARTITION' and a corresponding function | ||
| 10817 | to inplace_alter_table(). | ||
| 10818 | This will be invoked before inplace_alter_partition(). | ||
| 10819 | |||
| 10820 | @param[in,out] altered_table TABLE object for new version of table | ||
| 10821 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 10822 | by ALTER TABLE and holding data used during | ||
| 10823 | in-place alter. | ||
| 10824 | @param[in] old_dd_tab Table definition before the ALTER | ||
| 10825 | @param[in,out] new_dd_tab Table definition after the ALTER | ||
| 10826 | @retval true Failure | ||
| 10827 | @retval false Success */ | ||
| 10828 | 943 | bool ha_innopart::prepare_inplace_alter_partition( | |
| 10829 | TABLE *altered_table, Alter_inplace_info *ha_alter_info, | ||
| 10830 | const dd::Table *old_dd_tab, dd::Table *new_dd_tab) { | ||
| 10831 | 943 | clear_ins_upd_nodes(); | |
| 10832 | |||
| 10833 | 943 | trx_start_if_not_started_xa(m_prebuilt->trx, true, UT_LOCATION_HERE); | |
| 10834 | |||
| 10835 |
3/4✓ Branch 0 taken 593 times.
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 943 times.
|
1536 | if (alter_parts::need_copy(ha_alter_info) && |
| 10836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 593 times.
|
593 | prepare_for_copy_partitions(ha_alter_info)) { |
| 10837 | ✗ | my_error(ER_OUT_OF_RESOURCES, MYF(0)); | |
| 10838 | ✗ | return (true); | |
| 10839 | } | ||
| 10840 | |||
| 10841 | 943 | alter_parts *ctx = ut::new_withkey<alter_parts>( | |
| 10842 | 943 | UT_NEW_THIS_FILE_PSI_KEY, m_prebuilt->trx, m_part_share, ha_alter_info, | |
| 10843 | 943 | m_part_info, m_new_partitions); | |
| 10844 | |||
| 10845 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 943 times.
|
943 | if (ctx == nullptr) { |
| 10846 | ✗ | my_error(ER_OUT_OF_RESOURCES, MYF(0)); | |
| 10847 | ✗ | return (true); | |
| 10848 | } | ||
| 10849 | |||
| 10850 | 943 | ha_alter_info->handler_ctx = ctx; | |
| 10851 | |||
| 10852 | 943 | int error = ctx->prepare(*old_dd_tab, *new_dd_tab, altered_table); | |
| 10853 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 855 times.
|
868 | if (error != 0) { |
| 10854 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR)); |
| 10855 | } | ||
| 10856 | 868 | return (error); | |
| 10857 | } | ||
| 10858 | |||
| 10859 | 855 | bool ha_innopart::inplace_alter_partition(Alter_inplace_info *ha_alter_info) { | |
| 10860 |
3/4✓ Branch 0 taken 855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332 times.
✓ Branch 3 taken 523 times.
|
855 | if (!alter_parts::need_copy(ha_alter_info)) { |
| 10861 | 332 | return (false); | |
| 10862 | } | ||
| 10863 | |||
| 10864 | /* The lock type can be set as none, since in this step, the | ||
| 10865 | shared table lock is held, thus no other changes. This is to fix | ||
| 10866 | if the table was explicitly lock, then select_lock_type in the | ||
| 10867 | prebuilt here would not be LOCK_NONE, then row locks would be | ||
| 10868 | required; if we finally want to drop the original partitions, | ||
| 10869 | these row locks would lead to failure/crash. */ | ||
| 10870 | 523 | ulint lock_type = m_prebuilt->select_lock_type; | |
| 10871 | 523 | m_prebuilt->select_lock_type = LOCK_NONE; | |
| 10872 | |||
| 10873 |
1/2✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
|
523 | prepare_change_partitions(); |
| 10874 | |||
| 10875 | 523 | partition_info *old_part_info = table->part_info; | |
| 10876 | |||
| 10877 |
1/2✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
|
523 | set_part_info(ha_alter_info->modified_part_info, true); |
| 10878 | |||
| 10879 |
1/2✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
|
523 | prepare_change_partitions(); |
| 10880 | |||
| 10881 | ulonglong deleted; | ||
| 10882 | int res; | ||
| 10883 | |||
| 10884 |
1/2✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
|
523 | res = copy_partitions(&deleted); |
| 10885 | |||
| 10886 |
1/2✓ Branch 0 taken 523 times.
✗ Branch 1 not taken.
|
523 | set_part_info(old_part_info, false); |
| 10887 | |||
| 10888 | 523 | m_prebuilt->select_lock_type = lock_type; | |
| 10889 | |||
| 10890 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 494 times.
|
523 | if (res > 0) { |
| 10891 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
29 | print_error(res, MYF(res != ER_OUTOFMEMORY ? 0 : ME_FATALERROR)); |
| 10892 | } | ||
| 10893 | |||
| 10894 | 523 | return (res); | |
| 10895 | } | ||
| 10896 | |||
| 10897 | /** Prepare to commit or roll back ALTER TABLE...ALGORITHM=INPLACE. | ||
| 10898 | This is for 'ALTER TABLE ... PARTITION' and a corresponding function | ||
| 10899 | to commit_inplace_alter_table(). | ||
| 10900 | @param[in,out] altered_table TABLE object for new version of table. | ||
| 10901 | @param[in,out] ha_alter_info ALGORITHM=INPLACE metadata | ||
| 10902 | @param[in] commit true=Commit, false=Rollback. | ||
| 10903 | @param[in] old_dd_tab old table | ||
| 10904 | @param[in,out] new_dd_tab new table | ||
| 10905 | @retval true on failure (my_error() will have been called) | ||
| 10906 | @retval false on success */ | ||
| 10907 | 868 | bool ha_innopart::commit_inplace_alter_partition( | |
| 10908 | TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit, | ||
| 10909 | const dd::Table *old_dd_tab, dd::Table *new_dd_tab) { | ||
| 10910 | 868 | alter_parts *ctx = static_cast<alter_parts *>(ha_alter_info->handler_ctx); | |
| 10911 | 868 | m_prebuilt->table = nullptr; | |
| 10912 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 868 times.
|
868 | if (ctx == nullptr) { |
| 10913 | ✗ | ut_ad(!commit); | |
| 10914 | ✗ | return (false); | |
| 10915 | } | ||
| 10916 | |||
| 10917 |
2/2✓ Branch 0 taken 826 times.
✓ Branch 1 taken 42 times.
|
868 | if (commit) { |
| 10918 | 826 | int error = ctx->try_commit(*old_dd_tab, *new_dd_tab, table, altered_table); | |
| 10919 |
1/2✓ Branch 0 taken 776 times.
✗ Branch 1 not taken.
|
776 | if (!error) { |
| 10920 | 776 | ut::delete_(ctx); | |
| 10921 | 776 | ha_alter_info->handler_ctx = nullptr; | |
| 10922 | |||
| 10923 | 776 | ut::delete_(m_new_partitions); | |
| 10924 | 776 | m_new_partitions = nullptr; | |
| 10925 | |||
| 10926 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 662 times.
|
776 | if (altered_table->found_next_number_field) { |
| 10927 | 114 | dd_set_autoinc(new_dd_tab->se_private_data(), | |
| 10928 | 114 | m_part_share->next_auto_inc_val); | |
| 10929 | } | ||
| 10930 | |||
| 10931 | 776 | dd_copy_table(ha_alter_info, *new_dd_tab, *old_dd_tab); | |
| 10932 | 776 | dd_part_adjust_table_id(new_dd_tab); | |
| 10933 | |||
| 10934 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 739 times.
|
776 | if (dd_table_has_instant_cols(*old_dd_tab)) { |
| 10935 | 37 | dd_inplace_alter_copy_instant_metadata(ha_alter_info, old_dd_tab, | |
| 10936 | new_dd_tab); | ||
| 10937 | } | ||
| 10938 | } | ||
| 10939 | |||
| 10940 | 776 | return (error != 0); | |
| 10941 | } | ||
| 10942 | |||
| 10943 | 42 | ctx->rollback(); | |
| 10944 | 42 | ut::delete_(ctx); | |
| 10945 | 42 | ha_alter_info->handler_ctx = nullptr; | |
| 10946 | |||
| 10947 | 42 | ut::delete_(m_new_partitions); | |
| 10948 | 42 | m_new_partitions = nullptr; | |
| 10949 | |||
| 10950 | 42 | return (false); | |
| 10951 | } | ||
| 10952 | |||
| 10953 | /** Check if the DATA DIRECTORY is specified (implicitly or explicitly) | ||
| 10954 | @param[in] dd_part The dd::Partition to be checked | ||
| 10955 | @retval true the DATA DIRECTORY is specified (implicitly or explicitly) | ||
| 10956 | @retval false otherwise */ | ||
| 10957 | 203 | static bool dd_part_has_datadir(const dd::Partition *dd_part) { | |
| 10958 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | ut_ad(dd_part_is_stored(dd_part)); |
| 10959 | |||
| 10960 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | return (dd_part->options().exists(data_file_name_key) || |
| 10961 |
3/4✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 109 times.
|
175 | (dd_part->parent() != nullptr && |
| 10962 |
7/12✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 66 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 66 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 66 times.
✗ Branch 11 not taken.
|
647 | dd_part->parent()->options().exists(data_file_name_key)) || |
| 10963 |
4/10✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 175 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 175 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
553 | dd_part->table().se_private_data().exists( |
| 10964 |
3/4✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 28 times.
|
581 | dd_table_key_strings[DD_TABLE_DATA_DIRECTORY])); |
| 10965 | } | ||
| 10966 | |||
| 10967 | /** Adjust data directory for exchange partition. Special handling of | ||
| 10968 | dict_table_t::data_dir_path is necessary if DATA DIRECTORY is specified. For | ||
| 10969 | exaple if DATA DIRECTORY Is '/tmp', the data directory for nomral table is | ||
| 10970 | '/tmp/t1', while for partition is '/tmp'. So rename, the postfix table name 't1' | ||
| 10971 | should either be truncated or appended. | ||
| 10972 | @param[in] table_p partiton table | ||
| 10973 | @param[in] table_s swap table*/ | ||
| 10974 | 28 | void exchange_partition_adjust_datadir(dict_table_t *table_p, | |
| 10975 | dict_table_t *table_s) { | ||
| 10976 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | ut_ad(table_s->n_ref_count == 1); |
| 10977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | ut_ad(table_p->n_ref_count == 1); |
| 10978 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (table_s->data_dir_path != nullptr) { |
| 10979 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | std::string str(table_s->data_dir_path); |
| 10980 | /* new_name contains database/name but we require name */ | ||
| 10981 | 28 | const char *name = strchr(table_s->name.m_name, '/') + 1; | |
| 10982 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | str.append(name); |
| 10983 | |||
| 10984 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | ulint old_size = mem_heap_get_size(table_s->heap); |
| 10985 | |||
| 10986 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | table_s->data_dir_path = mem_heap_strdup(table_s->heap, str.c_str()); |
| 10987 | |||
| 10988 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | ulint new_size = mem_heap_get_size(table_s->heap); |
| 10989 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | dict_sys_mutex_enter(); |
| 10990 | 28 | dict_sys->size += new_size - old_size; | |
| 10991 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | dict_sys_mutex_exit(); |
| 10992 | 28 | } | |
| 10993 | |||
| 10994 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 17 times.
|
28 | if (table_p->data_dir_path != nullptr) { |
| 10995 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | std::string str(table_p->data_dir_path); |
| 10996 | 11 | size_t found = str.find_last_of("/\\"); | |
| 10997 | |||
| 10998 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | ut_ad(found != std::string::npos); |
| 10999 | 11 | found++; | |
| 11000 | |||
| 11001 | 11 | table_p->data_dir_path[found] = '\0'; | |
| 11002 | 11 | } | |
| 11003 | 28 | } | |
| 11004 | |||
| 11005 | /** Exchange partition. | ||
| 11006 | Low-level primitive which implementation is provided here. | ||
| 11007 | @param[in] part_id The id of the partition to be exchanged | ||
| 11008 | @param[in] part_table partitioned table to be exchanged | ||
| 11009 | @param[in] swap_table table to be exchanged | ||
| 11010 | @return error number | ||
| 11011 | @retval 0 on success */ | ||
| 11012 | 212 | int ha_innopart::exchange_partition_low(uint part_id, dd::Table *part_table, | |
| 11013 | dd::Table *swap_table) { | ||
| 11014 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | DBUG_TRACE; |
| 11015 | |||
| 11016 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(part_table != nullptr); |
| 11017 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(swap_table != nullptr); |
| 11018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(m_part_share != nullptr); |
| 11019 |
2/4✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 212 times.
|
212 | ut_ad(dd_table_is_partitioned(*part_table)); |
| 11020 |
2/4✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 212 times.
|
212 | ut_ad(!dd_table_is_partitioned(*swap_table)); |
| 11021 |
3/6✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 212 times.
|
212 | ut_ad(innobase_strcasecmp(part_table->name().c_str(), |
| 11022 | table_share->table_name.str) == 0); | ||
| 11023 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(part_id < m_tot_parts); |
| 11024 | 212 | std::vector<dd::Partition_index *> part_indexes; | |
| 11025 | 212 | std::vector<dd::Partition_index *>::iterator p_iter; | |
| 11026 | 212 | std::vector<dd::Index *> swap_indexes; | |
| 11027 | 212 | std::vector<dd::Index *>::iterator s_iter; | |
| 11028 | #ifdef UNIV_DEBUG | ||
| 11029 | 212 | std::vector<dd::Index *> part_table_indexes; | |
| 11030 | 212 | std::vector<dd::Index *>::iterator pt_iter; | |
| 11031 | #endif | ||
| 11032 | |||
| 11033 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | if (high_level_read_only) { |
| 11034 | ✗ | my_error(ER_READ_ONLY_MODE, MYF(0)); | |
| 11035 | ✗ | return HA_ERR_TABLE_READONLY; | |
| 11036 | } | ||
| 11037 | |||
| 11038 |
3/6✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 212 times.
|
424 | if (dd_table_has_instant_cols(*part_table) || |
| 11039 |
2/4✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 212 times.
|
212 | dd_table_has_instant_cols(*swap_table)) { |
| 11040 | ✗ | my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0), | |
| 11041 | "INSTANT COLUMN(s)"); | ||
| 11042 | ✗ | return true; | |
| 11043 | } | ||
| 11044 | |||
| 11045 | /* Find the specified dd::Partition object */ | ||
| 11046 | 212 | uint id = 0; | |
| 11047 | 212 | dd::Partition *dd_part = nullptr; | |
| 11048 |
2/4✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 429 times.
✗ Branch 3 not taken.
|
429 | for (auto part : *part_table->leaf_partitions()) { |
| 11049 |
1/2✓ Branch 0 taken 429 times.
✗ Branch 1 not taken.
|
429 | ut_d(dict_table_t *table = m_part_share->get_table_part(id)); |
| 11050 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 429 times.
|
429 | ut_ad(table->n_ref_count == 1); |
| 11051 |
2/4✓ Branch 0 taken 429 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 429 times.
|
429 | ut_ad(!table->is_temporary()); |
| 11052 | |||
| 11053 |
2/2✓ Branch 0 taken 212 times.
✓ Branch 1 taken 217 times.
|
429 | if (++id > part_id) { |
| 11054 | 212 | dd_part = part; | |
| 11055 | 212 | break; | |
| 11056 | } | ||
| 11057 | } | ||
| 11058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(dd_part != nullptr); |
| 11059 | |||
| 11060 |
4/8✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 212 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 212 times.
|
424 | if (dd_part->options().exists(index_file_name_key) || |
| 11061 |
3/6✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 212 times.
|
212 | swap_table->options().exists(index_file_name_key)) { |
| 11062 | ✗ | my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0), "INDEX DIRECTORY"); | |
| 11063 | ✗ | ut_d(ut_error); | |
| 11064 | ut_o(return true); | ||
| 11065 | } | ||
| 11066 | |||
| 11067 | /* Get the innodb table objects of part_table and swap_table */ | ||
| 11068 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | const table_id_t table_id = swap_table->se_private_id(); |
| 11069 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | dict_table_t *part = m_part_share->get_table_part(part_id); |
| 11070 | dict_table_t *swap; | ||
| 11071 | 212 | const auto hash_value = ut::hash_uint64(table_id); | |
| 11072 | |||
| 11073 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | dict_sys_mutex_enter(); |
| 11074 |
7/12✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 212 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 213 times.
✓ Branch 8 taken 212 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 213 times.
✗ Branch 11 not taken.
|
213 | HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *, |
| 11075 | swap, ut_ad(swap->cached), swap->id == table_id); | ||
| 11076 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | dict_sys_mutex_exit(); |
| 11077 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(swap != nullptr); |
| 11078 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
|
212 | ut_ad(swap->n_ref_count == 1); |
| 11079 | |||
| 11080 | #ifdef UNIV_DEBUG | ||
| 11081 | /* Store and sort part_table indexes */ | ||
| 11082 |
6/12✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 212 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 212 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 212 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 212 times.
✗ Branch 11 not taken.
|
212 | std::copy(part_table->indexes()->begin(), part_table->indexes()->end(), |
| 11083 | std::back_inserter(part_table_indexes)); | ||
| 11084 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | std::sort(part_table_indexes.begin(), part_table_indexes.end(), |
| 11085 | 99 | [](dd::Index *a, dd::Index *b) { return (a->name() < b->name()); }); | |
| 11086 | #endif | ||
| 11087 |
1/2✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
|
212 | dd::Object_id p_se_id = dd_part->se_private_id(); |
| 11088 | |||
| 11089 | /* Try to rename files. Tablespace checking ensures that | ||
| 11090 | both partition and table are of implicit tablespace. The plan is: | ||
| 11091 | 1. Rename the swap table to the intermediate file | ||
| 11092 | 2. Rename the partition to the swap table file | ||
| 11093 | 3. Rename the intermediate file of swap table to the partition file */ | ||
| 11094 | 212 | THD *thd = m_prebuilt->trx->mysql_thd; | |
| 11095 | 212 | char *swap_name = strdup(swap->name.m_name); | |
| 11096 | 212 | char *part_name = strdup(part->name.m_name); | |
| 11097 | |||
| 11098 | /* Define the temporary table name, by appending TMP_POSTFIX */ | ||
| 11099 | char temp_name[FN_REFLEN]; | ||
| 11100 | 212 | snprintf(temp_name, sizeof temp_name, "%s%s", swap_name, | |
| 11101 | dict_name::TMP_POSTFIX); | ||
| 11102 | |||
| 11103 | 212 | int error = 0; | |
| 11104 |
1/2✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
|
212 | error = innobase_basic_ddl::rename_impl<dd::Table>( |
| 11105 | thd, swap_name, temp_name, swap_table, swap_table, nullptr); | ||
| 11106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
|
209 | if (error != 0) { |
| 11107 | ✗ | goto func_exit; | |
| 11108 | } | ||
| 11109 |
1/2✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
|
209 | error = innobase_basic_ddl::rename_impl<dd::Partition>( |
| 11110 | thd, part_name, swap_name, dd_part, dd_part, nullptr); | ||
| 11111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
|
206 | if (error != 0) { |
| 11112 | ✗ | goto func_exit; | |
| 11113 | } | ||
| 11114 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
206 | error = innobase_basic_ddl::rename_impl<dd::Table>( |
| 11115 | thd, temp_name, part_name, swap_table, swap_table, nullptr); | ||
| 11116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | if (error != 0) { |
| 11117 | ✗ | goto func_exit; | |
| 11118 | } | ||
| 11119 | |||
| 11120 |
5/6✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 175 times.
|
378 | if (dd_part_has_datadir(dd_part) || |
| 11121 |
3/6✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 175 times.
|
175 | swap_table->options().exists(data_file_name_key)) { |
| 11122 | /* after above swaping swap is now partition table and part is now normal | ||
| 11123 | table */ | ||
| 11124 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | exchange_partition_adjust_datadir(swap, part); |
| 11125 | } | ||
| 11126 | |||
| 11127 |
6/12✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 203 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 203 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 203 times.
✗ Branch 11 not taken.
|
203 | std::copy(dd_part->indexes()->begin(), dd_part->indexes()->end(), |
| 11128 | std::back_inserter(part_indexes)); | ||
| 11129 |
6/12✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 203 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 203 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 203 times.
✗ Branch 11 not taken.
|
203 | std::copy(swap_table->indexes()->begin(), swap_table->indexes()->end(), |
| 11130 | std::back_inserter(swap_indexes)); | ||
| 11131 | |||
| 11132 | /* Sort the index pointers according to the index names because the index | ||
| 11133 | ordanility of the partition being exchanged may be different than the | ||
| 11134 | table being swapped */ | ||
| 11135 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | std::sort(part_indexes.begin(), part_indexes.end(), |
| 11136 | 81 | [](dd::Partition_index *a, dd::Partition_index *b) { | |
| 11137 | 81 | return (a->name() < b->name()); | |
| 11138 | }); | ||
| 11139 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | std::sort(swap_indexes.begin(), swap_indexes.end(), |
| 11140 | 79 | [](dd::Index *a, dd::Index *b) { return (a->name() < b->name()); }); | |
| 11141 | |||
| 11142 | /* Swap the se_private_data and options between indexes. | ||
| 11143 | The se_private_data should be swapped between every index of | ||
| 11144 | dd_part and swap_table; however, options should be swapped(checked) | ||
| 11145 | between part_table and swap_table */ | ||
| 11146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | ut_ad(part_indexes.size() == swap_indexes.size()); |
| 11147 | 203 | for (p_iter = part_indexes.begin(), s_iter = swap_indexes.begin(); | |
| 11148 |
5/6✓ Branch 0 taken 244 times.
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✓ Branch 5 taken 203 times.
|
447 | p_iter < part_indexes.end() && s_iter < swap_indexes.end(); |
| 11149 | 244 | p_iter++, s_iter++) { | |
| 11150 | 244 | auto part_index = *p_iter; | |
| 11151 | 244 | auto swap_index = *s_iter; | |
| 11152 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | dd::Object_id p_tablespace_id = part_index->tablespace_id(); |
| 11153 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | part_index->set_tablespace_id(swap_index->tablespace_id()); |
| 11154 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | swap_index->set_tablespace_id(p_tablespace_id); |
| 11155 | |||
| 11156 |
5/10✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 244 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 244 times.
|
244 | ut_ad(part_index->se_private_data().empty() == |
| 11157 | swap_index->se_private_data().empty()); | ||
| 11158 |
5/10✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 244 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 244 times.
|
244 | ut_ad(part_index->se_private_data().size() == |
| 11159 | swap_index->se_private_data().size()); | ||
| 11160 | |||
| 11161 |
3/6✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
|
244 | if (!part_index->se_private_data().empty()) { |
| 11162 | std::unique_ptr<dd::Properties> p_se_data( | ||
| 11163 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | dd::Properties::parse_properties("")); |
| 11164 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | p_se_data->insert_values(part_index->se_private_data()); |
| 11165 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | part_index->se_private_data().clear(); |
| 11166 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | part_index->set_se_private_data(swap_index->se_private_data()); |
| 11167 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
|
244 | swap_index->se_private_data().clear(); |
| 11168 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | swap_index->set_se_private_data(*p_se_data); |
| 11169 | 244 | } | |
| 11170 | } | ||
| 11171 | #ifdef UNIV_DEBUG | ||
| 11172 | 203 | for (s_iter = swap_indexes.begin(), pt_iter = part_table_indexes.begin(); | |
| 11173 |
5/6✓ Branch 0 taken 244 times.
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✓ Branch 5 taken 203 times.
|
447 | s_iter < swap_indexes.end() && pt_iter < part_table_indexes.end(); |
| 11174 | 244 | pt_iter++, s_iter++) { | |
| 11175 | 244 | auto part_table_index = *pt_iter; | |
| 11176 | 244 | auto swap_index = *s_iter; | |
| 11177 | |||
| 11178 |
5/10✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 244 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 244 times.
|
244 | ut_ad(part_table_index->options().raw_string() == |
| 11179 | swap_index->options().raw_string()); | ||
| 11180 | } | ||
| 11181 | #endif | ||
| 11182 | |||
| 11183 | /* Swap the se_private_data and options of the two tables. | ||
| 11184 | Only the max autoinc should be set to both tables */ | ||
| 11185 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 171 times.
|
203 | if (m_part_share->get_table_share()->found_next_number_field) { |
| 11186 | 32 | uint64_t part_autoinc = part->autoinc; | |
| 11187 | 32 | uint64_t swap_autoinc = swap->autoinc; | |
| 11188 | 32 | uint64_t max_autoinc = std::max(part_autoinc, swap_autoinc); | |
| 11189 | |||
| 11190 |
2/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | dd_set_autoinc(swap_table->se_private_data(), max_autoinc); |
| 11191 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | dd_set_autoinc( |
| 11192 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | part_table->se_private_data(), |
| 11193 | 32 | std::max<uint64>(swap_autoinc, m_part_share->next_auto_inc_val)); | |
| 11194 | |||
| 11195 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | dict_table_autoinc_lock(part); |
| 11196 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | dict_table_autoinc_initialize(part, max_autoinc); |
| 11197 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | dict_table_autoinc_unlock(part); |
| 11198 | |||
| 11199 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31 times.
|
32 | if (m_part_share->next_auto_inc_val < swap_autoinc) { |
| 11200 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | lock_auto_increment(); |
| 11201 | 1 | m_part_share->next_auto_inc_val = swap_autoinc; | |
| 11202 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | unlock_auto_increment(); |
| 11203 | } | ||
| 11204 | } | ||
| 11205 | |||
| 11206 | /* Swap the se_private_id between partition and table */ | ||
| 11207 | |||
| 11208 |
2/4✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
|
203 | dd_part->set_se_private_id(swap_table->se_private_id()); |
| 11209 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | swap_table->set_se_private_id(p_se_id); |
| 11210 | |||
| 11211 |
6/10✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 950 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 950 times.
✓ Branch 9 taken 203 times.
|
1153 | for (auto dd_column : *swap_table->columns()) { |
| 11212 |
3/6✓ Branch 0 taken 950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 950 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 950 times.
✗ Branch 5 not taken.
|
950 | dd_column->se_private_data().set(dd_index_key_strings[DD_TABLE_ID], |
| 11213 | p_se_id); | ||
| 11214 | } | ||
| 11215 | |||
| 11216 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | dd_part_adjust_table_id(part_table); |
| 11217 | |||
| 11218 | 203 | func_exit: | |
| 11219 | 203 | free(swap_name); | |
| 11220 | 203 | free(part_name); | |
| 11221 | |||
| 11222 | 203 | return error; | |
| 11223 | 203 | } | |
| 11224 |